std::is_scalar<U...>::value
问题在于is_scalar
只接受一个类型参数的事实。您需要编写一个组合多个布尔值的包装器。我还想知道如果您只想要标量类型,为什么要使用完美转发 - 只需按值传递它们。这样,您也不必担心U
在传递左值时被推断为引用。
#include <type_traits>
template<bool B>
using bool_ = std::integral_constant<bool, B>;
template<class Head, class... Tail>
struct all_of
: bool_<Head::value && all_of<Tail...>::value>{};
template<class Head>
struct all_of<Head> : bool_<Head::value>{};
template<class C, class T = void>
using EnableIf = typename std::enable_if<C::value, T>::type;
// constructor
template<typename... U>
vector(U... args, EnableIf<all_of<std::is_scalar<U>...>>::type* = 0)
{
unpack_tuple(std::tie(args...)); // tie makes a tuple of references
}
上面的代码应该可以工作。但是,作为建议,如果您不想要某样东西,static_assert
那就不要得到它,也不要为此滥用 SFINAE。:) SFINAE 应该只在重载的上下文中使用。
// constructor
template<typename... U>
vector(U... args)
{
static_assert(all_of<std::is_scalar<U>...>::value, "vector only accepts scalar types");
unpack_tuple(std::tie(args...)); // tie makes a tuple of references
}
对于您的实际问题,我推荐了一种更好的方法来解包元组(或一般的可变参数,甚至是数组),使用索引技巧:
template<unsigned...> struct indices{};
template<unsigned N, unsigned... Is> struct indices_gen : indices_gen<N-1, N-1, Is...>{};
template<unsigned... Is> struct indices_gen<0, Is...> : indices<Is...>{};
template<unsigned... Is, class... U>
void unpack_args(indices<Is...>, U... args){
[](...){}((store[Is] = args, 0)...);
}
template<class... U>
vector(U... args){
static_assert(all_of<std::is_scalar<U>...>::value, "vector only accepts scalar types");
unpack_args(indices_gen<sizeof...(U)>(), args...);
}
这段代码所做的是“滥用”可变参数拆包机制。首先,我们生成一组索引[0 .. sizeof...(U)-1]
,然后将这个列表与args
. 我们将此扩展放在可变参数(非模板)函数参数列表中,因为包扩展只能发生在特定位置,这就是其中之一。另一种可能性是作为本地数组:
template<unsigned... Is, class... U>
void unpack_args(indices<Is...>, U... args){
int a[] = {(store[Is] = args, 0)...};
(void)a; // suppress unused variable warnings
}