4

I have encountered a C++ template conundrum. I've tried to trim it down to the bare minimum, and now I'm not even sure if what I'm trying to do is possible. Take a look at the following code (in some .h file).

template<typename T>
class A
{
public:
    template<typename S>
    void f(S x);
};

class B1 { };

template<typename S>
class B2 { };

//This one works:
template<>
template<typename S>
void A<B1>::f(S x)
{
}    

//This one does not work:
template<>
template<typename S>
void A<B2<S>>::f(S x)
{
}

In my main function I have something like this:

//This one works:
A<B1> first;
first.f<int>(5);

//This one does not work:
A<B2<int>> second;
second.f<int>(5);

The error message I get because of the second part is

error C3860: template argument list following class
             template name must list parameters in the
             order used in template parameter list

error C3855: 'A<T>': template parameter 'T' is
             incompatible with the declaration

Any idea what the problem is?


Edit

To make the problem more concrete, here's my motivation. I want the function f above to have specializations for T=std::tuple<T1, T2>, T=std::tuple<T1, T2, T3>, and T=std::tuple<T1, T2, T3, T4>, where the types in the tuple are still unbound.

Timothy Shields
  • 75,459
  • 18
  • 120
  • 173

3 Answers3

4

You are trying to partially specialize a member function template. That is not possible, I'm afraid...

Paul Michalik
  • 4,331
  • 16
  • 18
4

Your code has two problems. First, the second specialization is illegal, because

template<> // parameters useable for the specialization of A you refer to
           // since it is a function, no partial specialization is allowed.
template<typename S> // parameters for the function's parameters
void A<B2<S>>          // S can not be used here!
             ::f(S x)  // only here
{
}

If I change that to

template<>
template<typename S>
void A<B2<int>>::f(S x)
{
}

it works and now the second problem is exposed:

second.f<B2<int>>(5);

This sets S to B2<int> and the function expect a parameter S x - but the integer 5 can not be converted to that type. Change it to:

B2<int> x;
second.f<B2<int>>(x);

and it works as well.

Note that this might not solve the problem you were trying to solve, it just explains what happens.


Thinking about your edit: I think the fact that you try to specialize for T=std::tuple<...> already points the direction: T is the template parameter of A and that is what you should specialize. Maybe something like:

template< typename T >
class F // used to implement f(), so you can specialize
        // just F/f() instead of the whole class A
{
  void f(T x) { /* default impl */ }
};

template< typename T1, typename T2 >
class F< std::tuple< T1, T2 > >
{
  void f(T1 x, T2 y) { /* special impl */ }
};

template< typename T >
class A : public F< T >
{
    // ...other stuff...
};
Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
1

If you want to pass another template to a template, you have to use template template parameters, so your A<> template would look like this:

template<typename T>
class A
{
public:
    template<template <typename> class H, typename S>
    void f(H<S> x);
};

Now you can pass a template to your template.

I don't think you can specialize on template template parameters if your original template didn't take such an parameter type.

Community
  • 1
  • 1
Tony The Lion
  • 61,704
  • 67
  • 242
  • 415