10

Here is my code:

template<typename T1, typename T2> class MyClass
{
public:
    template<int num> static int DoSomething();
};

template<typename T1, typename T2> template<int num> int MyClass<T1, T2>::DoSomething()
{
    cout << "This is the common method" << endl;
    cout << "sizeof(T1) = " << sizeof(T1) << endl;
    cout << "sizeof(T2) = " << sizeof(T2) << endl;
    return num;
}

It works well. But when I try to add this

template<typename T1, typename T2> template<> int MyClass<T1, T2>::DoSomething<0>()
{
    cout << "This is ZERO!!!" << endl;
    cout << "sizeof(T1) = " << sizeof(T1) << endl;
    cout << "sizeof(T2) = " << sizeof(T2) << endl;
    return num;
}

I get compiller errors: invalid explicit specialization before «>» token template-id «DoSomething<0>» for «int MyClass::DoSomething()» does not match any template declaration

I use g++ 4.6.1 What should I do?

antpetr89
  • 1,143
  • 3
  • 12
  • 14

4 Answers4

10

Unfortunately, you can't specialise a template that's a member of a class template, without specialising the outer template:

C++11 14.7.3/16: In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well.

I think your best option is to add the extra parameter to MyClass, and then partially specialise that.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • But the example is not explicitly specialising a class member template - it's specialising a function member template. So the part you have highlighted doesn't apply and the permission given in the previous part of the sentence seems to apply. – Alan Stokes Feb 14 '12 at 12:32
  • 2
    @AlanStokes: "Class member template" means a template that's a member of a class - it could be a template for either a function or a nested class. "Member class template" would specifically refer to a class template that's a member (per the use of that term in 14.7.3/1). GCC, at least, uses that interpretation. – Mike Seymour Feb 14 '12 at 12:46
  • 14.5.2/1 suggests a template that's a member of a class is just a "member template". "class member template" doesn't seem to be a defined term. Yuck. But it looks like [DR 529](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#529) will clarify this to agree with your answer. – Alan Stokes Feb 14 '12 at 13:14
  • Does anyone know why this is? I've found a bunch of explanations that just explain that you can't do it, but no mention of any rational. – Casey Rodarmor Feb 25 '12 at 23:41
1

Old question, I know,

but I stumbled uppon the same problem in my current project and found a workaround which does the job at least for template arguments which are no types but values (like template <int num>).

The implementation of my solution:

template<class T> template<int num> void Classname<T>::methodname()
{
    if (num == 0)
    {
        //implementation for num == 0
    }
    else if (num == 1)
    {
        //implementation for num == 1
    }
    //more cases...
}

num == constant will evaluate to a constant expression so the compiler will optimize your code to just keep the correct implementation for each case.

Please correct me if I'm wrong or if something makes this a bad solution ;)

DocValle
  • 125
  • 2
  • 10
0

Similar to DocValle answer, not to rely on possible compiler optimisation

you could use constexpr if to enforce compile time branching

template<class T> template<int num> void Classname<T>::methodname()
{
    if constexpr (num == 0)
    {
        //implementation for num == 0
    }
    else if constexpr (num == 1)
    {
        //implementation for num == 1
    }
    //more cases...
}
0

That is sad but true: you cannot explicitly specialize a class template unless its enclosing class templates are also explicitly specialized. For more information you may read

Below I've specialized MyClass first and everything got done.

#include <iostream>
using namespace std;

template<typename T1, typename T2> class MyClass
{
public:
  template<int num> static int DoSomething();
};

template<typename T1, typename T2> template<int num> int MyClass<T1, T2>::DoSomething()
{
  cout << "This is the common method" << endl;
  cout << "sizeof(T1) = " << sizeof(T1) << endl;
  cout << "sizeof(T2) = " << sizeof(T2) << endl;
  return num;
}

template<> template<> int MyClass<char, int>::DoSomething<0>()
{
  cout << "This is ZERO!!!" << endl;
  cout << "sizeof(T1) = " << sizeof(char) << endl;
  cout << "sizeof(T2) = " << sizeof(int) << endl;
  return 0;
}

int main() {
  MyClass<char, int> m;
  m.DoSomething<2>();
  m.DoSomething<0>();
  return 0;
}

Output:

This is the common method
sizeof(T1) = 1
sizeof(T2) = 4
This is ZERO!!!
sizeof(T1) = 1
sizeof(T2) = 4

EUREKA! This works well on MSVCPP 10.

#include <iostream>
using namespace std;

template<typename T1, typename T2> class MyClass
{
public:
  template<int num> static int DoSomething();
  template<> static int DoSomething<0>() {
    cout << "This is ZERO!!!" << endl;
    cout << "sizeof(T1) = " << sizeof(T1) << endl;
    cout << "sizeof(T2) = " << sizeof(T2) << endl;
    return 0;
  }
};

template<typename T1, typename T2> template<int num> int MyClass<T1, T2>::DoSomething()
{
  cout << "This is the common method" << endl;
  cout << "sizeof(T1) = " << sizeof(T1) << endl;
  cout << "sizeof(T2) = " << sizeof(T2) << endl;
  return num;
}

int main() {
  MyClass<char, int> m;
  m.DoSomething<2>();
  m.DoSomething<0>();
  return 0;
}

Output:

This is the common method
sizeof(T1) = 1
sizeof(T2) = 4
This is ZERO!!!
sizeof(T1) = 1
sizeof(T2) = 4

BTW, do not return num; from specialization. It doesn't ever know what num is.

nickolay
  • 3,643
  • 3
  • 32
  • 40