【问题标题】:C++ STL type_traits questionC++ STL type_traits 问题
【发布时间】:2011-06-01 10:45:56
【问题描述】:

我在看最新的C9 lecture,发现了一些有趣的东西..

在他对 type_traits 的介绍中,Stephan 使用了以下(如他所说,人为的)示例:

template <typename T> void foo(T t, true_type)
{
    std::cout << t << " is integral";
}
template &lt;typename T&gt; void foo(T t, false_type)
{
    std::cout << t << " is not integral";
}

template &lt;typename T&gt; void bar(T t) { foo(t, typename is_integral&lt;T&gt;::type()); }

这似乎比:

template &lt;typename T&gt; void foo(T t)
{
    if(std::is_integral&lt;T&gt;::value)
        std::cout << "integral";
    else
        std::cout << "not integral";
}

后一种方式有问题吗?他的方式更好吗?为什么?

谢谢。

【问题讨论】:

  • 在 C++17 中我们有 if constexpr。

标签: c++ templates stl typetraits


【解决方案1】:

基本上,第一个选项在编译时使用关于类型“完整性”的知识,而第二个选项 - 将此知识转移到运行时。

这意味着我们可以将不可编译用于非整数类型的代码用于整数类型。

【讨论】:

  • +1 这是最重要的一点。即使foo 不支持这两种类型,这也允许调用bar 工作。
【解决方案2】:

下面的例子应该说明差异。让我们添加结构 X:

struct X
{
  X(int)
  {
  }
};

并修改一个 foo 如下:

template <typename T> void foo(T t, true_type)
{
    std::cout << t << " is integral";
    X x(t);
}
template <typename T> void foo(T t, false_type)
{
    std::cout << t << " is not integral";
}

然后:

template <typename T> void bar(T t)
{
    foo(t, typename is_integral<T>::type());
}

仍将为所有 T 类型编译(包括整数类型;它可能会导致警告但会编译)。

其他等效代码:

template <typename T> void foo(T t)
{
    if(std::is_integral<T>::value)
    {
        std::cout << "integral";
        X x(t);
    }
    else
        std::cout << "not integral";
}

通常会编译失败,因为您将无法为除整数以外的类型实例化 X,最终浮点和具有运算符 int() 的用户定义类(运算符 short() 或运算符 long() 不会这样做) .

【讨论】:

  • 优秀的答案!这完美地解释了它。谢谢。
【解决方案3】:

对于这样一个人为的小例子,第一种方法并没有太大的优势。当您遇到更复杂的情况时,优势就来了。它本质上类似于在面向对象编程中使用基于继承的多态性或 if/switch 语句。更复杂的解决方案为您提供更大的灵活性;无需修改现有代码即可轻松添加类型。

如果您知道您将需要的所有类型(例如,您使用的是布尔值,例如),那么更简单的解决方案可能会更好。但是,如果您没有固定的需求(以及需求何时固定?),从长远来看,更复杂但更灵活的解决方案可能会更容易。

【讨论】:

    【解决方案4】:

    使用第一种方法,您可以不使用使用if/else 或switch 来实现静态调度。

    template <typename T> 
    void Dispatch(T t)
    {
        //Call foo(T, true_type) or foo(T, false_type)
        //depending upon the *type* of second parameter.
        foo(t, typename is_integral<T>::type());
    }
    

    使用第二种方法,您必须使用 if/else 或 switch 块来实现它,

    template <typename T> 
    void Dispatch(T t)
    {
        //Call foo(T, true_type) or foo(T, false_type)
        //depending upon the *value* of value.
        if(std::is_integral<T>::value)
            foo(t, true_type());
        else
            foo(t, false_type());
    }
    

    但是如果你想实现你的Dispatch()函数而不使用if/else,同时你想使用std::is_integral&lt;T&gt;::value,那么你必须重新编写你的foo()函数,像这样,

    template <bool b> 
    void foo(T t)
    {
        std::cout << t << " is integral";
    }
    
    template <> 
    void foo<false>(T t)
    {
        std::cout << t << " is not integral";
    }
    

    你的Dispatch() 函数看起来像,

     template <typename T> 
     void Dispatch(T t)
     {
         //using std::is_integral<T>::value!
         const bool selector = (bool) std::is_integral<T>::value;
         foo<selector>(t);
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多