Вопрос

Yes.

Let's say I have a simple variadic struct that holds a typedef:

template<typename... TArgs> struct TupleTypeHolder {
    using TupleType = std::tuple<TArgs*...>;
};

I want to pass TupleTypeHolder<something> as a template parameter to another class, and get that typedef.

All of my tries do not compile.

// None of these is valid
template<template<typename...> class TTupleTypeHolder> struct TupleMaker {
     using MyTupleType = TTupleTypeHolder::TupleType; // Not valid
     using MyTupleType = typename TTupleTypeHolder::TupleType; // Not valid
};

 template<template<typename... A> class TTupleTypeHolder> struct TupleMaker2 {
     // A is not a valid name here
     using MyTupleType = TTupleTypeHolder<A...>::TupleType; // Not valid
     using MyTupleType = typename TTupleTypeHolder<A...>::TupleType; // Not valid
};

Is there a way to use the variadic template parameters (in this case, TupleTypeHolder's TArgs...) of a variadic template class from a class that uses the aforementioned class as a template variadic template parameter?


Usage example:

template<typename... TArgs> struct TupleTypeHolder {
    using TupleType = std::tuple<TArgs*...>;
};

template<typename... TArgs> static int getSomeValue() { ... }

template<??? T1, ??? T2> class TupleMaker 
{ 
    std::pair<int, int> someValues;

    using TupleType1 = T1::TupleType;
    using TupleType2 = T2::TupleType;

    TupleMaker() : someValues{getSomeValue<T1's TArgs...>(), 
                             getSomeValue<T2's TArgs...>()} { }
};

class MyTupleMaker : TupleMaker<TupleTypeHolder<int, char>, 
                                TupleTypeHolder<int, float>> 
{ };

MyTupleMaker::TupleType1 tuple1{new int(1), new char('a')};  
MyTupleMaker::TupleType2 tuple1{new int(35), new float(12.f)};  
Это было полезно?

Решение

Working usage example:

#include <tuple>

template<typename... TArgs> struct TupleTypeHolder {
    using TupleType = std::tuple<TArgs*...>;
};

template<typename... TArgs> static int getSomeValue() { return 42; }

// primary template:
template<class T1, class T2>
struct TupleMaker;

// partial specialization:
template<template<class...> class TT1, template<class...> class TT2,
         class... T1, class... T2>
struct TupleMaker < TT1<T1...>, TT2<T2...> >
{ 
    std::pair<int, int> someValues;

    using TupleType1 = typename TT1<T1...>::TupleType;
    using TupleType2 = typename TT2<T2...>::TupleType;

    TupleMaker() : someValues{getSomeValue<T1...>(), 
                              getSomeValue<T2...>()} { }
};

struct MyTupleMaker : TupleMaker<TupleTypeHolder<int, char>, 
                                TupleTypeHolder<int, float>> 
{ };

MyTupleMaker::TupleType1 tuple1{new int(1), new char('a')};  
MyTupleMaker::TupleType2 tuple2{new int(35), new float(12.f)};  

int main() {}

The primary template takes two types, as you're passing types. TupleTypeHolder<int, char> is a type, a specialization of a template, not a template itself. Template template-parameters however take templates as arguments (not types), such as:

template<template<class...> class Foo>
struct Bar
{
    using type = Foo<int, double, char>;
};

Bar< std::tuple > b; // note: no template arguments for `std::tuple`!

With partial specialization, you can split a template specialization into the template and the parameters, that's how the above works.

Другие советы

Template-template parameters are not really type parameters, are parameters to specify a template. That means what you pass through a template-template parameter is not a type, is a template:

template<template<typename> class TPARAM>
struct give_me_a_template
{
    using param = TPARAM; //Error TPARAM is not a type, is a template.
    using param_bool = TPARAM<bool>; //OK, thats a type
};

As you can see, the first alias is invalid, because TPARAM is not a type, is a template. But the second is a type (Is an instance of the template).

That said, examine your problem: What you called TupleTypeHolder could be viewed as a variadic-template typelist. So your goal is to make tuples of the types specified with typelists, right?

You can use partial specialization to extract the content of a typelist:

template<typename TupleTypeHolder>
struct tuple_maker;

template<typename... Ts>
struct tuple_maker<TupleTypeHolder<Ts...>>
{
    using tuple_type = std::tuple<Ts...>;
};

An example of its usage could be:

using my_types = TupleTypeHolder<int,int,int>;
using my_tuple_type = typename tuple_maker<my_types>::tuple_type;

Of course this is not the exactly solution to your implementation, you need to extend the concept to multiple typelists (As your question showed). What I have provided is the guide to understand the problem and its solution.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top