考虑以下功能:
template <typename Type>
void f(const Type& x)
我想在其中做一些特殊的事情(没有专业化),无论传递的类型是空的std::tuple
还是空的std::array
。对于nu元素的元组,我可以使用std::is_same<Type, std::tuple<>>::value
但是我可以用什么技巧来检测零元素数组?
(我正在寻找一种不需要创建另一个函数或类的解决方案,......)
答案 0 :(得分:6)
您可以使用std::tuple_size
,因为它也适用于std::array
!见here。只需使用:
std::tuple_size<Type>::value == 0
检查Type
是空的std::tuple<>
还是空的std::array<T,0>
。
如果Type
既不是std::tuple
也不是std::array
,那么问题仍然存在。我看到的一般方法是:
constexpr bool IsNotTupleOrArray =
!std::is_class<Type>::value ||
std::is_same<Type,ExcludeThisClass>::value ||
sizeof(Type)>1 || // non-portable, works for GCC 4.8+
...;
std::conditional< IsNotTupleOrArray,
std::false_type,
std::tuple_size<Type> >::type::value;
这基本上意味着您必须明确排除其他类型。例如,is_class<Type>
排除所有基本类型,如int
,指针等。
答案 1 :(得分:3)
如果你不想在没有专业化的情况下这样做,为什么不用重载呢? ;)专业化功能模板有时(通常)不是一个坏主意。使用一些SFINAE技巧,创建仅在这两个条件适用时选择的重载并不困难。
但是,我已经听到你大声说这不是你想要做的事情:你想要的是if
内部的某种f()
,如果条件为真,它将被执行,并且当条件为假时将执行的相应else
分支。
但是,请注意,这不是static if,而是常规运行时,如果:换句话说,编译器在编译时会100%确定地知道这两个分支中的一个永远不会将被执行(它可能会发出一个恼人的警告),但它必须解析两个分支并证明它们是合法的。
实际上,这意味着您将无法放置依赖于特定类型T
(或T
的属性)的语句,以便可编译。例如,在下面的代码中compile_time_expression
确定类型T
是否具有成员函数foo()
或成员函数bar()
:
T obj;
if (compile_time_expression)
{
obj.foo();
}
else
{
obj.bar();
}
但是,如果特定T
没有 成员函数foo()
和成员函数bar()
,则上述代码将无法编译:你在这里有一个运行时if
,编译器必须解析两个分支并确保它们都是可编译的 - 然后可能优化掉永远不会被执行的分支。
不幸的是,C ++没有任何构造,如静态if(还是?),所以重载+ SFINAE是解决这个问题的正确方法。