【问题标题】:C++ class template constructor making decision based on typeC++ 类模板构造函数根据类型做出决策
【发布时间】:2018-01-02 01:38:12
【问题描述】:

我发现了一个类似的问题here,但它并没有具体回答我的问题。我有一个简单的类模板,它只需要一个参数。它不存储任何成员变量,并且除了简单的构造函数之外没有任何方法。根据传入的类型,我需要在构造函数中分支我的逻辑。对于我正在尝试做的事情,该类的简单版本外壳看起来像这样。该类将对Type t进行一些处理,并将结果通过引用存储到std::string中。

template<class Type>
struct Test {
    Test( Type t, std::string& str ) {
        static_assert( std::is_arithmetic<Type>::value, "Arithmetic type required." );
        if ( std::is_arithmetic<Type>::value ) { // check if type is arithmetic
            // some variables here

            // Note: I do not want to static_assert here if type is integral. 
            // If assert fails the else will not be executed.
            if ( std::is_integral<type>::value ) {

                // some code for integral types
            } else {

                // some other code for arithmetic non integral types (floating point types)
            }
            str = // some code.

        } else {
            // possibly throw some exception
        }
    }
};

这是基于data type 解决分支决策的适当方法吗?还是有更理想的有效方式来做到这一点?

  • 我可以有一个带有几个成员变量和重载 2 或 3 个函数的默认构造函数
  • 我可以对课程进行部分专业化(不是首选)。
  • 我可以完全消除“类结构”并将其作为函数模板执行,但是,我更愿意实例化这种类型的对象。

【问题讨论】:

  • if 更改为 C++17 的 if constexpr
  • @O'Neil 我对 C++17 的支持有限
  • @O'Neil 好的,令我惊讶的是;当项目设置中的字段留空时,Visual Studio 2017 CE 被设置为默认 C++14。有一个标志可以将其设置为 C++17 或 C++latest。我不得不做一些研究来找出答案。所以我确实支持if constexpr( ... ) { }。我确实知道 MS Visual Studio 仅限于 C++17 的某些功能,而不是 clang or gcc。漂亮的小保安! :)

标签: c++11 templates c++14 overloading partial-specialization


【解决方案1】:

混合标签调度和委托构造函数怎么样?

我的意思是……类似

template <typename Type>
struct Test
 {
   Test (Type t, std::string & str, std::true_type const &,
         std::true_type const &)
    { str = "case arithmetic and integral"; }

   Test (Type t, std::string & str, std::true_type const &,
         std::false_type const &)
    { str = "case arithmetic but not integral"; }

   Test (Type t, std::string & str, std::false_type const &, ...)
    { str = "case not arithmetic"; /* + throw ? */ }

   Test (Type t, std::string & str)
      : Test(t, str, std::is_arithmetic<Type>{}, std::is_integral<Type>{})
    { }
};


int main ()
 { 
   std::string  str;

   Test<int>(0, str);

   std::cout << str << std::endl;

   Test<float>(0.0f, str);

   std::cout << str << std::endl;

   Test<std::string>("zero", str);

   std::cout << str << std::endl;
 }

如果公共代码相关,您可以为算术类型定义单个委托构造函数,并使用在正文中调用的成员进行标记调度。

那是

template <typename Type>
struct Test
 {
   void func (std::string & str, std::true_type const &)
    { str = "case integral"; }

   void func (std::string & str, std::false_type const &)
    { str = "case not integral"; }

   Test (Type t, std::string & str, std::true_type const &)
    {
      // variable definition and common code

      func(str, /* other variables */ std::is_integral<Type>{});

      // other common code 
      str += " plus common";
    }

   Test (Type t, std::string & str, std::false_type const &)
    { str = "case not arithmetic"; /* + throw ? */ }

   Test (Type t, std::string & str)
      : Test(t, str, std::is_arithmetic<Type>{})
    { }
};

【讨论】:

  • 经过一番研究;我发现在 MS Visual Studio 2017 的项目设置中有一个空白字段,将默认编译器设置为(/std:c++14)。该标志可以设置为(/std:c++17)(/std:c++latest)。所以我确实支持c++17。我很喜欢你的回答;但我想我将通过在 if 语句中添加constexpr 来对我的问题发表评论。它让生活变得更加轻松......尽管您使用tag dispatching 的解决方案确实让读者用户更容易更好地理解构造函数。
  • @FrancisCugler - 我同意:如果你可以使用 C++17,if constexpr 是最好的选择。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-23
  • 2021-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多