简体   繁体   English

来自单个整数参数的可变参数模板声明?

[英]Variadic template declaration from single integer argument?

Is it possible to statically declare N same-type template arguments from single integer type template argument?是否可以从单个整数类型模板参数静态声明N 个相同类型的模板参数? Potentially something similar to this:可能与此类似的内容:

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;
    /* ... */
}

I understand I can use a variadic template and use it directly to the member instance declaration, but I was wondering if there would be some kind of SFINAE implementation that would resolve a single integer template parameter, as the syntax would be much cleaner and intuitive.我知道我可以使用可变参数模板并将其直接用于成员实例声明,但我想知道是否会有某种 SFINAE 实现可以解析单个整数模板参数,因为语法会更清晰和直观。

One possible solution, using tuples and helper templates to assemble the desired class.一种可能的解决方案,使用元组和辅助模板来组装所需的类。 A little additional sugar can make the resulting syntax "cleaner" Tested with gcc 10.2:一点额外的糖可以使生成的语法“更干净” 用 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;
}

You can write a meta-function that accepts N , base_t , and SomeOtherClass , and recursively calls itself with a smaller N , each time tacking on base_t to the end of a growing parameter pack:您可以编写一个接受Nbase_tSomeOtherClass的元函数,并使用较小的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;
};

For the base case, when N goes down to 0, the meta-function yields SomeOtherClass instantiated with the parameter pack of N base_t types:对于基本情况,当N下降到 0 时,元函数产生SomeOtherClassN base_t类型的参数包实例化:

template <typename T, template<typename...> typename C, typename ...Ts>
struct expand<0, T, C, Ts...> { 
    using type = C<Ts...>;
};

Also, convenience alias is nice to avoid having to say typename at the call site:此外,便利别名可以很好地避免在调用站点上说typename

template <int N, typename T, template<typename...> typename C>
using expand_t = typename expand<N, T, C>::type;

Now at the call site you can write:现在在呼叫站点你可以写:

expand_t<N, base_t, SomeOtherClass> foo; 
// equivalent to 
// SomeOtherClass< base_t, base_t, ..., base_t > foo;
//               ^^^        N times          ^^^ 

Here's a demo .这是一个演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM