Search code examples
c++c++11templatesvariadic-templatestemplate-specialization

Call template specialization with more parameters for specific value of one-parameter template call


I have a template that takes 2 parameters. For a certain value of the first parameter, I know what the second parameter should be. I would like to have only one full definition of my template (the one that takes 2 arguments), and be able to instantiate my template supplying only one argument.

In the following example, I know that if the first template parameter is Foo1, the second should be Foo2. I'd like to be able to create a Someclass<Foo1,Foo2> by writing Someclass<Foo1>.

#include <iostream>
using namespace std;

struct Foo1 { Foo1() { cout << "Foo1 "; }};
struct Foo2 { Foo2() { cout << "Foo2 "; }};

template <typename ...Dummy> struct SomeClass;
template <typename T, typename U> struct SomeClass<T,U> {
  SomeClass() {
    T t;
    U u;
  }
};

/* Here, some one-argument specialization where if SomeClass<Foo1> is desired,
 * SomeClass<Foo1, Foo2> is obtained. */

int main() {
  SomeClass<Foo1, Foo2> c; //prints "Foo1 Foo2 "
  SomeClass<Foo1> c2;      //Should print the same thing, right now "incomplete type"
}

I guess I'm going to have to make a specialization that takes 2 arguments, the first being Foo1, like so:

template <typename U> struct SomeClass<Foo1, U> {
  SomeClass() {
    Foo1 f;
    U u;
  }
};

But how do I make a specialization that accepts only one parameter Foo1 and results in a SomeClass<Foo1,Foo2> ?


Solution

  • The simplest solution for the case of a class template would probably be to define a specialization that matches the case you're interested in and have that "forward" to the specialization with the arguments you want that to map to by inheriting from it:

    template <typename ...Dummy>
    struct SomeClass
    {
        // default implementation
    };
    
    template <typename T, typename U>
    struct SomeClass<T, U>
    {
        // case for two parameters
    };
    
    template <> struct SomeClass<Foo1> : public SomeClass<Foo1, Foo2> {};