2

Sorry I didn't know how to find a great title for this question, feel free to edit.

I have a range of classes that have the same role, meaning that they all implement the same interface (set of methods). Consider that they all inherit from the same abstract class (even if it's not the case in the minimal example; it's not the point of this question). These classes are all templated.

I want to define a class taking to templates arguments, say T and U, and one of the previous classes A without template arguments. Internally, this new class will use A<T> and A<U>. Is this possible? C++11 answers are welcome, feel free to add the tag if necessary.

The example that fails is here:

#include <iostream>

// ------------------------------------------------------------------------

struct eng_tag {};
struct fr_tag {};
struct sp_tag {};

// First implementation of the "talk interface"
template <class T = eng_tag> struct A
{
    void talk() { std::cout<<"Hello\n"; }
};
template <> struct A<fr_tag>
{
    void talk() { std::cout<<"Salut\n"; }
};
template <> struct A<sp_tag>
{
    void talk() { std::cout<<"Ola\n"; }
};

// Second implementations
template <class T = eng_tag> struct B
{
    void talk() { std::cout<<"Bye\n"; }
};
template <> struct B<fr_tag>
{
    void talk() { std::cout<<"A bientot\n"; }
};
template <> struct B<sp_tag>
{
    void talk() { std::cout<<"Adios\n"; }
};

// etc...

// ------------------------------------------------------------------------

template <class T, class U, class I = A>
struct Wrapper
{
    I<T> one() { return I<T>(); }
    I<U> two() { return I<U>(); }
};

// ------------------------------------------------------------------------

int main()
{
    Wrapper<fr_tag,sp_tag,B> w;
        w.one().talk();
        w.two().talk();
}
Jonathan H
  • 7,591
  • 5
  • 47
  • 80
  • 1
    It looks like you need "template template parameters". See http://stackoverflow.com/questions/213761/what-are-some-uses-of-template-template-parameters-in-c. – juanchopanza Apr 21 '14 at 12:50

1 Answers1

5

A is a template, not a type. So what you need is a template template parameter ([1],[2]):

template <class T, class U, template<typename> class I = A>
//                          ^^^^^^^^^^^^^^^^^^^^^^^^^^ template template parameter
struct B
{
    I<T> one() { return I<T>(); }
    I<U> two() { return I<U>(); }
};
Community
  • 1
  • 1
jrok
  • 54,456
  • 9
  • 109
  • 141
  • Interesting, I have never seen that before, I'll try it :) (Sorry for editing my post, `B` is no longer the name of this class, I just called it `Wrapper` instead). – Jonathan H Apr 21 '14 at 12:52
  • @Sh3ljohn: If *this is the answer*, please accept it so that it is clear to other SO users. As a side note, you could change the `Wrapper` to take `I` and `I` instead of `T`, `U`, and `I<>`; at least in the code you show, where `T` and `U` are never used by themselves. – David Rodríguez - dribeas Apr 21 '14 at 13:07
  • @DavidRodríguez-dribeas SO requires a minimum amount of time before accepting an answer, that's why I didn't do it earlier. I have a small additional question if I'm not being too demanding. What if `A` takes more than one template argument, but that I'm only interested in one of them? Can I define a "meta-type"? Something like `template using Meta = A` perhaps? – Jonathan H Apr 21 '14 at 13:16
  • @Sh3ljohn In C++11 you can do it using alias templates. – Constructor Apr 21 '14 at 13:34
  • 1
    @Sh3ljohn: The details are important there, do all of the templates have the same number (and type) of arguments? If so you can provide default values in the template template argument: `template< ..., template class I >` (or something alike (i.e. you might need to provide names to the arguments). Now a different question is whether that is the cleaner design you can do... – David Rodríguez - dribeas Apr 21 '14 at 13:35
  • @Constructor: Without further explanation, it is not so obvious how you could do that. I mean, the user can create all of the alias templates and then pass the alias template, but this cannot be done in the `Wrapper` template, and I am not sure that the needs of the `Wrapper` template should be imposed on all users of the `I` template... – David Rodríguez - dribeas Apr 21 '14 at 13:37