具有相同类型的可变模板参数的构造函数无法编译
constructor with variadic template arguments of the same type does not compile
我正在尝试构建一个 class 使用可变模板构造函数。
模板参数都是同一类型。
我正在使用带有 C++ 17 的 Visual C++ 编译器,但代码没有生成;此代码实际上使编译器崩溃。
这在 C++17 中可能吗?
struct Alfa {
template<int... T>
Alfa(const T&... all_args) {
std::tuple<T...> data(all_args...);
}
};
Alfa alfa(1,2,3,4);
您必须决定是否需要非类型模板参数。您的代码首先说 "the T
are integer values",但随后尝试像函数签名和 tuple
模板参数列表中的类型一样使用 T
。
有效选项为:
struct Alfa {
template<class ... Ts>
Alfa(const Ts&... all_args) {
std::tuple<Ts...> data(all_args...);
}
};
Alfa alfa(1,2,3,4);
这不对 "all Ts
have to be the same" 的约束进行编码。没有直接的方法可以做到这一点。您可以使用 static_assert
或 SFINAE(参见其他答案)。
template<int... Is>
struct Alfa {
Alfa() {
std::tuple data(Is...); // Using class template argument deduction.
}
};
Alfa<1,2,3,4> alfa{};
此模板 class,而不是构造函数,这很可能不是您想要的。它显示了接受编译时整数值(即非类型模板参数包)的语法。但是您不能对非类型模板参数使用推导,因此必须明确指定它们。但这是构造函数的impossible!
妥协可能是:
struct Alfa {
template<class ... Ts>
Alfa(const Ts&... all_args) {
std::tuple<Ts...> data(all_args...);
}
};
template<int ... Is>
auto makeAlfa() { return Alfa(Is...); }
Alfa alfa = makeAlfa<1,2,3,4>();
The template arguments are all the same type. [...] is that possible in C++17 ?
是的,有可能。
但不是这么简单,而且有一些缺点。
您可以编写接受不同类型参数的构造函数;这很简单
template <typename ... Ts>
Alfa (const Ts & ... as)
{ std::tuple<Ts...> data{as...}; }
但这允许 Ts...
类型不同。
您可以使用 SFINAE 强制所有类型都相同,如下所示
template <typename T, typename ... Ts,
std::enable_if_t<(std::is_same_v<T, Ts> && ...), bool> = true>
Alfa (T const & a0, Ts const & ... as)
{
std::tuple<T, Ts...> data0{a0, as...};
std::array data1{a0, as...};
}
因此只有当第一个 T
之后的所有 Ts...
类型与 T
完全相同时,您的构造函数才会启用
缺点:适用于
Alfa alfa{1, 2, 3, 4};
但是
出错
Alfa alfa{1l, 2l, 3, 4l}; <-- 3 isn't long
因为 3
可以转换为 long
(1l
是 long
)但不是 long
。
因此您可以检查以下 Ts...
是否可转换为 T
,而不是它们是否相等
template <typename T, typename ... Ts,
std::enable_if_t<(std::is_convertible_v<Ts, T> && ...), bool> = true>
Alfa (T const & a0, Ts const & ... as)
{
std::tuple<T, Ts...> data0{a0, as...};
std::array<T, sizeof...(Ts)+1u> data1{a0, as...};
}
但是这样你就可以让 T
对其他类型更重要(如果所有 Ts...
都可以转换为 T
但如果 T
可以转换为Ts...
) 之一,所以我认为更好的解决方案是检查是否存在通用类型
template <typename ... Ts,
typename CT = std::common_type_t<Ts...>>
Alfa (Ts const & ... as)
{
std::tuple<Ts...> data0{as...};
std::array<CT, sizeof...(Ts)> data1{as...};
}
我正在尝试构建一个 class 使用可变模板构造函数。 模板参数都是同一类型。
我正在使用带有 C++ 17 的 Visual C++ 编译器,但代码没有生成;此代码实际上使编译器崩溃。
这在 C++17 中可能吗?
struct Alfa {
template<int... T>
Alfa(const T&... all_args) {
std::tuple<T...> data(all_args...);
}
};
Alfa alfa(1,2,3,4);
您必须决定是否需要非类型模板参数。您的代码首先说 "the T
are integer values",但随后尝试像函数签名和 tuple
模板参数列表中的类型一样使用 T
。
有效选项为:
struct Alfa {
template<class ... Ts>
Alfa(const Ts&... all_args) {
std::tuple<Ts...> data(all_args...);
}
};
Alfa alfa(1,2,3,4);
这不对 "all Ts
have to be the same" 的约束进行编码。没有直接的方法可以做到这一点。您可以使用 static_assert
或 SFINAE(参见其他答案)。
template<int... Is>
struct Alfa {
Alfa() {
std::tuple data(Is...); // Using class template argument deduction.
}
};
Alfa<1,2,3,4> alfa{};
此模板 class,而不是构造函数,这很可能不是您想要的。它显示了接受编译时整数值(即非类型模板参数包)的语法。但是您不能对非类型模板参数使用推导,因此必须明确指定它们。但这是构造函数的impossible!
妥协可能是:
struct Alfa {
template<class ... Ts>
Alfa(const Ts&... all_args) {
std::tuple<Ts...> data(all_args...);
}
};
template<int ... Is>
auto makeAlfa() { return Alfa(Is...); }
Alfa alfa = makeAlfa<1,2,3,4>();
The template arguments are all the same type. [...] is that possible in C++17 ?
是的,有可能。
但不是这么简单,而且有一些缺点。
您可以编写接受不同类型参数的构造函数;这很简单
template <typename ... Ts>
Alfa (const Ts & ... as)
{ std::tuple<Ts...> data{as...}; }
但这允许 Ts...
类型不同。
您可以使用 SFINAE 强制所有类型都相同,如下所示
template <typename T, typename ... Ts,
std::enable_if_t<(std::is_same_v<T, Ts> && ...), bool> = true>
Alfa (T const & a0, Ts const & ... as)
{
std::tuple<T, Ts...> data0{a0, as...};
std::array data1{a0, as...};
}
因此只有当第一个 T
之后的所有 Ts...
类型与 T
缺点:适用于
Alfa alfa{1, 2, 3, 4};
但是
出错 Alfa alfa{1l, 2l, 3, 4l}; <-- 3 isn't long
因为 3
可以转换为 long
(1l
是 long
)但不是 long
。
因此您可以检查以下 Ts...
是否可转换为 T
,而不是它们是否相等
template <typename T, typename ... Ts,
std::enable_if_t<(std::is_convertible_v<Ts, T> && ...), bool> = true>
Alfa (T const & a0, Ts const & ... as)
{
std::tuple<T, Ts...> data0{a0, as...};
std::array<T, sizeof...(Ts)+1u> data1{a0, as...};
}
但是这样你就可以让 T
对其他类型更重要(如果所有 Ts...
都可以转换为 T
但如果 T
可以转换为Ts...
) 之一,所以我认为更好的解决方案是检查是否存在通用类型
template <typename ... Ts,
typename CT = std::common_type_t<Ts...>>
Alfa (Ts const & ... as)
{
std::tuple<Ts...> data0{as...};
std::array<CT, sizeof...(Ts)> data1{as...};
}