3

考虑以下函数:

template <typename Type>
void f(const Type& x)

std::tuple无论传递的类型是空的还是空的,我都想做一些特别的事情(没有专门化)std::array。对于 nu 元素的元组,我可以使用,std::is_same<Type, std::tuple<>>::value但是我可以使用什么技巧来检测零元素数组?

(我正在寻找不需要创建另一个函数或类的解决方案,...)

4

2 回答 2

6

您可以使用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、 指针等。

于 2013-03-19T21:27:39.000 回答
3

如果您不想在没有专业化的情况下这样做,为什么不使用重载呢?;) 专门化一个函数模板有时(不,经常)是个坏主意。使用一些 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 是解决这个问题的正确方法

于 2013-03-19T21:09:42.537 回答