5

我正在观看最新的C9 讲座,并注意到一些有趣的事情。

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

template <typename T> void foo(T t, true_type)
{
    std::cout << t << " is integral";
}
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()); }

这似乎远比:

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

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

谢谢。

4

4 回答 4

14

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

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

于 2010-12-30T08:20:29.413 回答
9

下面的示例应该说明差异。让我们添加结构 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() 不会这样做)。

于 2010-12-30T17:44:18.033 回答
1

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

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

于 2010-12-30T08:02:24.753 回答
0

使用第一种方法,您可以在不使用if/elseor的情况下实现静态调度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/elseswitch块来实现它,

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<T>::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);
 }
于 2010-12-30T09:55:55.537 回答