C++ variadic template template argument that matches any kind of parameters

后端 未结 3 1187
野的像风
野的像风 2021-01-30 16:38

I was wondering if it\'s possible to write a template function that can take any other arbitrary template as a parameter and properly match the template name (i.e. not just the

相关标签:
3条回答
  • 2021-01-30 17:16

    You must have a metafunction that rebinds the type of container. Because you cannot just replace first template parameter:

    vector<int, allocator<int> > input;
    vector<double, allocator<int> > just_replaced;
    vector<double, allocator<double> > properly_rebound;
    

    So, just write such a metafunction for known set of containers.

    template<class Container, class NewValue> class rebinder;
    
    // example for vectors with standard allocator
    template<class V, class T> class rebinder< std::vector<V>, T > {
    public:
      typedef std::vector<T> type;
    };
    // example for lists with arbitrary allocator
    template<class V, class A, class T> class rebinder< std::list<V,A>, T > {
      typedef typename A::template rebind<T>::other AT; // rebind the allocator
    public:
      typedef std::list<T,AT> type; // rebind the list
    };
    // example for arrays
    template<class V, size_t N> class rebinder< std::array<V,N>, T > {
    public:
      typedef std::array<T,N> type;
    };
    

    Rules of rebinding may vary for different containers.

    Also you might require a metafunction that extracts value type from arbitrary container, not only std-conformant (typedef *unspecified* value_type)

    template<class Container> class get_value_type {
    public:
      typedef typename Container::value_type type; // common implementation
    };
    template<class X> class get_value_type< YourTrickyContainer<X> > {
      ......
    public:
      typedef YZ type;
    };
    
    0 讨论(0)
  • 2021-01-30 17:26

    It would be awesome if we had such thing, as it would allow us to write a is_same_template trait in a breeze.
    Until then, we specialize all the way.

    0 讨论(0)
  • 2021-01-30 17:34

    Your interesting construct has two levels with variadic templates.

    • An outer variadic template parameter list TemplateP & Sizes for a function template
    • An inner parameter pack as the template parameters of your template template parameter TemplateT, a class template

    First, let's look at the inner TemplateT class: why can the ellipsis operator not not match something like TemplateT< int, 2 >? Well, the standard defines variadic templates in §14.5.3 as

    template<class ... Types> struct Tuple { };
    template<T ...Values> struct Tuple2 { };
    

    where the template argument pack in the first case may only match types and in the second version only values of type T. In particular,

    Tuple < 0 >    error;  // error, 0 is not a type!
    Tuple < T, 0 > error2; // T is a type, but zero is not!
    Tuple2< T >    error3; // error, T is not a value
    Tuple2< T, 0 > error4; // error, T is not a value
    

    are all malformed. Furthermore, it is not possible to fall back to something like

    template<class ... Types, size_t ...Sizes> struct Tuple { };
    

    because the standard states in §14.1.11:

    If a template-parameter of a primary class template or alias template is a template parameter pack, it shall be the last template-parameter. A template parameter pack of a function template shall not be followed by another template parameter unless that template parameter can be deduced from the parameter-type-list of the function template or has a default argument (14.8.2).

    In other words, for class templates only one variadic parameter pack may appear in the definition. Therefore the above (double)-variadic class definition is malformed. Because the inner class always needs such a combination, it is impossible to write something as general as you conceived.


    What can be rescued? For the outer function template, some shards can be put together, but you won't like it. As long as the second parameter pack can be deduced from the first, two parameter packs may appear (in a function template). Therefore, a function such as

    template < typename... Args, size_t... N > void g(const std::array< Args, N > &...arr);
    g(std::array< double, 3 >(), std::array< int, 5>());
    

    is allowed, because the integer values can be deduced. Of course, this would have to be specialized for every container type and is far from what you had imagined.

    0 讨论(0)
提交回复
热议问题