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〕或
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()); } |
使用第二种方法,您必须使用
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()); } |
但是如果你想在不使用
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"; } |
你的
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); } |