如何在此示例中为所有参数设置相同的类型?

时间:2015-03-04 20:25:11

标签: c++ c++11 variadic-templates

只是为了练习我正在尝试编写一个可变参数模板,将一些值输入到矢量中。我写了以下内容:

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。

2 个答案:

答案 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...);
}