0

Given this code:

template <typename K, typename V>
class Foo{
    typedef K valueTypeK;
    typedef V valueTypeV;
};

template<class... Foo>
class Bar{
public:
    // capture Foo... parameter package
    using FooTuple = std::tuple<Foo...>;

};

template <class... Foo>
class Data{
    // capture Foo... parameter package
    using FooTuple = std::tuple<Foo...>;
};

// assuming T inherits from Bar
template<class T>
class Container{
    // I'd like Data to be of type "Data<Foo...> "
    // but it will be of type "Data<std::tuple<Foo...>>"
    Data<typename T::FooTuple> data;
};

class BarImpl : public Bar<Foo<int, int>, Foo<int, float>, Foo<float, float>> {};

int main(){
    BarImpl bar_impl;
    Container<BarImpl> container_impl;
}

right now, in container_impl, the Data field will be of type

Data<std::tuple<Bar<Foo<int, int>, Foo<int, float>, Foo<float, float>>>

because that is how the parameter package was stored in Bar. But I want Data to be of type

Data<Bar<Foo<int, int>, Foo<int, float>, Foo<float, float>>

which would be how BarImpl was defined to begin with.

Can this be achieved somehow?

(Edit: fixed wrong var name)

user3641187
  • 405
  • 5
  • 10
  • why does `BarImpl` inherit from `Bar` ? I think what you actually want is `using BarImpl = Bar<, Foo, Foo>;` – 463035818_is_not_an_ai Mar 05 '23 at 18:11
  • Bar() is a virtual class, it would have overridden functions in a real-life setting – user3641187 Mar 05 '23 at 18:28
  • Essentially, I'd want Container to infer and re-use the parameter pack Foo... that was declared within the Container template T. The goal is to avoid having to manually re-declare Foo... in Container's template header as it is already stored in type T. – user3641187 Mar 05 '23 at 18:46

1 Answers1

0

I'd like Data to be of type Data<Foo...> but it will be of type Data<std::tuple<Foo...>>

You have to pick the type list from the inside of the template class like this helper shows:

template <typename> struct DataHelper;
template < template < typename ...> class OUTER, typename ... INNER >
struct DataHelper< OUTER<INNER...> >: public Data<INNER...>{};

As you may see we will declare a template which picks up any class. For a class which is a template class which holds a variadic list, we define a specialization. The specialization defines the INNER variadic list and we simply forward this by inheriting from your type Data.

Full example:

template <typename K, typename V>
class Foo{ 
    typedef K valueTypeK;
    typedef V valueTypeV;
};

template<class... Foo> 
class Bar{ 
public:
    // capture Foo... parameter package
    using FooTuple = std::tuple<Foo...>;

};

template <class... Foo> 
class Data{
    public:
    // capture Foo... parameter package
    using FooTuple = std::tuple<Foo...>;
};


template <typename> struct DataHelper;
template < template < typename ...> class OUTER, typename ... INNER >
struct DataHelper< OUTER<INNER...> >: public Data<INNER...>{};

template < typename T>
void Print()
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}


// assuming T inherits from Bar
template<class T>
class Container{
    // I'd like Data to be of type "Data<Foo...> "
    // but it will be of type "Data<std::tuple<Foo...>>"
    Data<typename T::FooTuple> data;
    DataHelper<typename T::FooTuple> dataHelper;

    public:

    void Check() 
    {    
        Print< typename decltype(data)::FooTuple> ();  
        Print< typename decltype(dataHelper)::FooTuple> ();  
    }    
};

class BarImpl : public Bar<Foo<int, int>, Foo<int, float>, Foo<float, float>> {};

int main(){
    BarImpl bar_impl;
    Container<BarImpl> container_impl;
    container_impl.Check();
}

BTW: You mix using and typedef inside your code. For me it is easier to read it in uniform syntax by generally use using instead!

Klaus
  • 24,205
  • 7
  • 58
  • 113