考虑以下函数:
template <typename Type>
void f(const Type& x)
std::tuple
无论传递的类型是空的还是空的,我都想做一些特别的事情(没有专门化)std::array
。对于 nu 元素的元组,我可以使用,std::is_same<Type, std::tuple<>>::value
但是我可以使用什么技巧来检测零元素数组?
(我正在寻找不需要创建另一个函数或类的解决方案,...)
考虑以下函数:
template <typename Type>
void f(const Type& x)
std::tuple
无论传递的类型是空的还是空的,我都想做一些特别的事情(没有专门化)std::array
。对于 nu 元素的元组,我可以使用,std::is_same<Type, std::tuple<>>::value
但是我可以使用什么技巧来检测零元素数组?
(我正在寻找不需要创建另一个函数或类的解决方案,...)
您可以使用std::tuple_size
,因为它也适用std::array
!见这里。只需使用:
std::tuple_size<Type>::value == 0
检查Type
是空std::tuple<>
的还是空的std::array<T,0>
。
综上所述,问题仍然是如果Type
既不是 a 又std::tuple
不是 a会发生什么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
、 指针等。
如果您不想在没有专业化的情况下这样做,为什么不使用重载呢?;) 专门化一个函数模板有时(不,经常)是个坏主意。使用一些 SFINAE 技巧,创建仅在这两个条件适用时才选择的重载并不难。
但是,我已经听到你在喊这不是你想要做的:你想要的是在条件为真时执行的某种if
内部,以及在条件为假时执行的相应分支。f()
else
但是,请注意,这不是静态if,而是常规运行时 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++ 没有任何构造,例如 static if (yet?),所以重载 + SFINAE 是解决这个问题的正确方法。