关于模板:C ++ STL type_traits问题

C++ STL type_traits question

我在看最新的C9讲座,发现了一些有趣的事情。

在介绍类型特征时,斯蒂芬使用了以下(如他所说,人为的)例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <wyn><typename T></wyn> void foo(T t, true_type)
{
    std::cout << t <<" is integral";
}
template <wyn><typename T></wyn> void foo(T t, false_type)
{
    std::cout << t <<" is not integral";
}
</p>

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

代码>

这似乎比:

1
2
3
4
5
6
7
template <wyn><typename T></wyn> void foo(T t)
{
    if(<wyn>std::is_integral<T>::value</wyn>)
        std::cout <<"integral";
    else
        std::cout <<"not integral";
}

代码>

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

谢谢。


基本上,第一个选项在编译时使用关于类型"完整性"的知识,第二个选项-将这些知识移动到运行时。

这意味着我们可以使用不可编译为非整型的整型代码。


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

1
2
3
4
5
6
struct X
{
  X(int)
  {
  }
};

修改一个foo如下:

1
2
3
4
5
6
7
8
9
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";
}

然后:

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

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

其他等效代码:

1
2
3
4
5
6
7
8
9
10
template <typename T> void foo(T t)
{
    if(std::is_integral<T>::value)
    {
        std::cout <<"integral";
        X x(t);
    }
    else
        std::cout <<"not integral";
}

通常无法编译,因为您将无法为除整数之外的类型以及最终具有operator int()(operator short()或operator long())的浮点类和用户定义类实例化x。


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

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


使用第一种方法,您可以在不使用OCx1〔0〕或switch的情况下实现静态调度。

1
2
3
4
5
6
7
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块来实现这一点,

1
2
3
4
5
6
7
8
9
10
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());
}

但是如果你想在不使用if/else的情况下实现Dispatch()功能,同时又想使用std::is_integral::value功能,那么你必须重新编写foo()功能,就像这样,

1
2
3
4
5
6
7
8
9
10
11
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()功能看起来像,

1
2
3
4
5
6
7
 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);
 }