只是为了练习我正在尝试编写一个可变参数模板,将一些值输入到矢量中。我写了以下内容:
template <class T>
void add(vector<T> *v, T n){
v->push_back(n);
}
template <class T, class... T2>
void add(vector<T> *v, T n, T2... rest){
v->push_back(n);
add(v, rest...);
}
为了测试这些,我使用以下内容:
vector<int> vI;
add(&vI, 10, 30, 25);
for (int i = 0; i < vI.size(); i++)
cout << vI[i] << endl;
一切都按预期工作,但我想知道第二个模板是否可以以只使用一种类型(T或T2)的方式编写,因为vector(push_back)期望所有参数都使用相同的类型?事实上,我想一直确保T = T2。
答案 0 :(得分:2)
有趣的是,您当前的代码已经确保了像
这样的调用add(&vI, 10, 10.f, 20);
没有编译。如果参数的类型与向量的值类型不同,那么最终它将成为调用中的第二个参数,如
add(&vI, 10.f, 20);
然后模板参数推断将失败,因为它推导出T
的冲突类型。
如果您希望在递归中深度发生演绎失败时减少可怕的错误消息量,SFINAE或static_assert
可以提供帮助。我个人更喜欢Columbo的伎俩:
template<bool...> class bool_pack;
template<bool...b>
using all_true = std::is_same<bool_pack<true, b...>, bool_pack<b..., true>>;
template <class T, class... T2>
void add(vector<T> *v, T n, T2... rest)
{
static_assert(all_true<std::is_same<T, T2>{}...>{}, "T2 must be all Ts");
v->push_back(n);
add(v, rest...);
}
目前无法避免同时使用T和T2(不修改通话)。然而,该委员会正在考虑该领域的潜在改进,因此有些东西可能会进入下一个标准。
答案 1 :(得分:1)
您可以创建一个元函数,以确保参数包T2
中的所有类型都等于T
。
template <typename T, typename ...Ts>
struct AllSame : public std::false_type{};
template <typename T>
struct AllSame<T> : public std::true_type{};
template <typename T, typename U, typename ...Ts>
struct AllSame<T, U, Ts...> : public std::conditional_t<std::is_same<T,U>::value, AllSame<T, Ts...>, std::false_type>{};
现在在返回类型上使用SFINAE:
template <class T, class... T2>
auto add(vector<T> *v, T n, T2... rest)
-> std::enable_if_t<AllSame<T, T2...>::value>
{
v->push_back(n);
add(v, rest...);
}