来自单个整数参数的可变参数模板声明?
Variadic template declaration from single integer argument?
是否可以从单个整数类型模板参数静态声明 N 个相同类型的模板参数?可能与此类似:
template < int N >
class MyTemplatedType {
// base type, known
typedef float base_t;
// instance of some other templated class with *N* template arguments
SomeOtherClass< base_t, base_t, base_t, base_t, ..., base_t > foo;
/* ... */
}
我知道我可以使用可变参数模板并将其直接用于成员实例声明,但我想知道是否会有某种 SFINAE 实现可以解析单个整数模板参数,因为语法是更简洁直观。
一种可能的解决方案,使用元组和辅助模板 assemble 所需的 class。一点额外的糖可以使生成的语法“更干净”使用 gcc 10.2 测试:
#include <tuple>
#include <type_traits>
// Create std::tuple<T ...>, with T repeated N times.
template<int N, typename T>
struct tuple_list : tuple_list<N-1, T> {
typedef decltype(std::tuple_cat(std::declval<typename tuple_list<N-1, T>
::tuple_t>(),
std::declval<std::tuple<T> &&>())
) tuple_t;
};
template<typename T>
struct tuple_list<0, T> {
typedef std::tuple<> tuple_t;
};
template<typename ...> struct SomeOtherClass {};
// And now, replace `std::tuple` with SomeOtherClass
template<typename tuple_t> struct make_some_other_class;
template<typename ...Args>
struct make_some_other_class<std::tuple<Args...>> {
typedef SomeOtherClass<Args...> type_t;
};
template < int N >
class MyTemplatedType {
typedef float base_t;
public:
// The payload is not exactly "clean", but one more helper
// template can make the syntax here a little bit nicer...
typename make_some_other_class< typename tuple_list<N, base_t>
::tuple_t >::type_t foo;
};
void foobar(MyTemplatedType<3> &bar)
{
SomeOtherClass<float, float, float> &this_works=bar.foo;
}
你可以编写一个接受N
、base_t
和SomeOtherClass
的元函数,并递归地用较小的N
调用自己,每次都添加base_t
到不断增长的参数包结束:
template <int N, typename T, template<typename...> typename C, typename ...Ts>
struct expand {
using type = typename expand<N-1, T, C, T, Ts...>::type;
};
对于基本情况,当 N
下降到 0 时,元函数产生 SomeOtherClass
用 N
base_t
类型的参数包实例化:
template <typename T, template<typename...> typename C, typename ...Ts>
struct expand<0, T, C, Ts...> {
using type = C<Ts...>;
};
此外,方便的别名可以避免在调用站点说 typename
:
template <int N, typename T, template<typename...> typename C>
using expand_t = typename expand<N, T, C>::type;
现在在调用站点你可以写:
expand_t<N, base_t, SomeOtherClass> foo;
// equivalent to
// SomeOtherClass< base_t, base_t, ..., base_t > foo;
// ^^^ N times ^^^
这是一个 demo。
是否可以从单个整数类型模板参数静态声明 N 个相同类型的模板参数?可能与此类似:
template < int N >
class MyTemplatedType {
// base type, known
typedef float base_t;
// instance of some other templated class with *N* template arguments
SomeOtherClass< base_t, base_t, base_t, base_t, ..., base_t > foo;
/* ... */
}
我知道我可以使用可变参数模板并将其直接用于成员实例声明,但我想知道是否会有某种 SFINAE 实现可以解析单个整数模板参数,因为语法是更简洁直观。
一种可能的解决方案,使用元组和辅助模板 assemble 所需的 class。一点额外的糖可以使生成的语法“更干净”使用 gcc 10.2 测试:
#include <tuple>
#include <type_traits>
// Create std::tuple<T ...>, with T repeated N times.
template<int N, typename T>
struct tuple_list : tuple_list<N-1, T> {
typedef decltype(std::tuple_cat(std::declval<typename tuple_list<N-1, T>
::tuple_t>(),
std::declval<std::tuple<T> &&>())
) tuple_t;
};
template<typename T>
struct tuple_list<0, T> {
typedef std::tuple<> tuple_t;
};
template<typename ...> struct SomeOtherClass {};
// And now, replace `std::tuple` with SomeOtherClass
template<typename tuple_t> struct make_some_other_class;
template<typename ...Args>
struct make_some_other_class<std::tuple<Args...>> {
typedef SomeOtherClass<Args...> type_t;
};
template < int N >
class MyTemplatedType {
typedef float base_t;
public:
// The payload is not exactly "clean", but one more helper
// template can make the syntax here a little bit nicer...
typename make_some_other_class< typename tuple_list<N, base_t>
::tuple_t >::type_t foo;
};
void foobar(MyTemplatedType<3> &bar)
{
SomeOtherClass<float, float, float> &this_works=bar.foo;
}
你可以编写一个接受N
、base_t
和SomeOtherClass
的元函数,并递归地用较小的N
调用自己,每次都添加base_t
到不断增长的参数包结束:
template <int N, typename T, template<typename...> typename C, typename ...Ts>
struct expand {
using type = typename expand<N-1, T, C, T, Ts...>::type;
};
对于基本情况,当 N
下降到 0 时,元函数产生 SomeOtherClass
用 N
base_t
类型的参数包实例化:
template <typename T, template<typename...> typename C, typename ...Ts>
struct expand<0, T, C, Ts...> {
using type = C<Ts...>;
};
此外,方便的别名可以避免在调用站点说 typename
:
template <int N, typename T, template<typename...> typename C>
using expand_t = typename expand<N, T, C>::type;
现在在调用站点你可以写:
expand_t<N, base_t, SomeOtherClass> foo;
// equivalent to
// SomeOtherClass< base_t, base_t, ..., base_t > foo;
// ^^^ N times ^^^
这是一个 demo。