如何为这个例子中的所有参数设置相同的类型?
How to set the same type for all arguments in this example?
只是为了练习,我正在尝试编写一个可变参数模板,将一些值输入到向量中。我写了以下内容:
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。
您可以创建一个元函数,确保参数包 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>{};
现在在您的 return 类型上使用 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...);
}
有趣的是,您当前的代码已经确保调用
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(不修改调用)。然而,委员会正在考虑在这方面的潜在改进,因此可能会进入下一个标准。
只是为了练习,我正在尝试编写一个可变参数模板,将一些值输入到向量中。我写了以下内容:
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。
您可以创建一个元函数,确保参数包 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>{};
现在在您的 return 类型上使用 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...);
}
有趣的是,您当前的代码已经确保调用
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(不修改调用)。然而,委员会正在考虑在这方面的潜在改进,因此可能会进入下一个标准。