5

When I use template partial specialization on a class with one template argument, I can specialize a method like this:

#include <cstdlib>

template< std::size_t Dim >
class Test
{
public:
  int foo();
};

template< std::size_t Dim >
inline int Test< Dim >::foo()
{
  return 0;
}

template<>
inline int Test< 1 >::foo()
{
  return 1;
}

int main()
{
  Test< 2 > wTest2;
  Test< 1 > wTest1;
  wTest2.foo();
  wTest1.foo();
  return 0;
}

The method foo is specialized for Dim = 1. But as soon as I add a template argument to my class, like this:

#include <cstdlib>

template< typename T, std::size_t Dim >
class Test
{
public:
  int foo();
};

template< typename T, std::size_t Dim >
inline int Test< T, Dim >::foo()
{
  return 0;
}

template< typename T >
inline int Test< T, 1 >::foo()
{
  return 1;
}

int main()
{
  Test< double, 2 > wTest2;
  Test< double, 1 > wTest1;
  wTest2.foo();
  wTest1.foo();
  return 0;
}

The compiler (of VS2010) complains with these errors:

1>c:\documents and settings\cayouette\my documents\codelocal\testtemplatespecialization\main.cpp(20): error C3860: template argument list following class template name must list parameters in the order used in template parameter list
1>c:\documents and settings\cayouette\my documents\codelocal\testtemplatespecialization\main.cpp(20): error C2995: 'int Test<T,Dim>::foo(void)' : function template has already been defined
1>          c:\documents and settings\cayouette\my documents\codelocal\testtemplatespecialization\main.cpp(7) : see declaration of 'Test<T,Dim>::foo'
1>c:\documents and settings\cayouette\my documents\codelocal\testtemplatespecialization\main.cpp(20): error C2976: 'Test<T,Dim>' : too few template arguments
1>c:\documents and settings\cayouette\my documents\codelocal\testtemplatespecialization\main.cpp(26): error C2264: 'Test<T,Dim>::foo' : error in function definition or declaration; function not called
1>          with
1>          [
1>              T=double,
1>              Dim=2
1>          ]
1>c:\documents and settings\cayouette\my documents\codelocal\testtemplatespecialization\main.cpp(27): error C2264: 'Test<T,Dim>::foo' : error in function definition or declaration; function not called
1>          with
1>          [
1>              T=double,
1>              Dim=1
1>          ]
1>
1>Build FAILED.

The way I see this, there is no ambiguity and the compiler should be able to resolve everything and work just like the one argument case.

If this is not supported in C++, please explain why.

  • 1
    dupe of this FAQ question: http://stackoverflow.com/questions/1501357/template-specialization-of-particular-members – Johannes Schaub - litb Oct 24 '11 at 20:51
  • Thanks Johannes, I did look for hours for that kind of answer without success. That being said, my question is a bit different, I am asking for the reason why it does not work, and so far, I do not have a definite answer. – Philippe Cayouette Oct 25 '11 at 13:20

2 Answers2

6

You cannot partially specialise functions – this includes member functions. You can only partially specialise the whole class:

template< typename T, std::size_t Dim >
class Test
{
public:
  int foo()
  {
    return 0;
  }
};

template< typename T >
class test< T, 1 >
{
public:
  int foo()
  {
    return 1;
  }
};

(I’ve defined the functions inline here; that of course isn’t necessary.)

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • Ok, the example with one template argument should have been called **full** specialization, not partial ; and this is probably why it works. However, I don't see any reason why partial specialization is not supported on member function, can you explain why? Is there any ambiguity or constraint for the compiler? – Philippe Cayouette Oct 24 '11 at 20:38
  • 1
    @Philippe I’m not sure why partial function templates are forbidden (but what they achieve can usually be solved via overloading). However, look at regu’s answer since my explanation is actually wrong, you are not partially specialising member functions. Still, the syntax you use is simply invalid for subtle reasons (you’re defining a member function for a partially specialised class but you don’t actually partially specialise this class in the first place). – Konrad Rudolph Oct 25 '11 at 09:04
  • What regu has suggested is what I have implemented in the first place, since I did not know the overload trick pointed by Johannes Schaub (http://stackoverflow.com/questions/1501357/template-specialization-of-particular-members) – Philippe Cayouette Oct 25 '11 at 13:24
6

Editing since I cannot post comments yet (50 rep heh)...

Philippe, in response to your comment this morning, according to the standard you cannot partially specialize a member of a class template, you can only fully specialize them (whether it be a class template, a function, a function template, etc...). In your first example, you are fully specializing the member function foo. In your second example, you are partially specializing, reason why it will not compile. You can fully specialize it this way:

template< >
inline int Test< int, 2 >::foo()
{...}

Although Konrad's code snipet is perfectly legal, I'm not sure the reason provided as to why Philippe's code doesn't compile is correct. (Although, as Konrad mentionned, you cannot partially specialize a function template).

The issue at hand, in Philippe's code, is that we are declaring a class template and not a function template. Hence, a partial class template specialization declaration is needed for the partial specialization definition to be legal.

#include <cstdlib>

template< typename T, std::size_t Dim >
class Test
{
public:
    int foo();
};

template < typename T >
class Test < T, 1 >
{
public:
    int foo();
};


template< typename T, std::size_t Dim >
inline int Test< T, Dim >::foo()
{
    return 0;
}

template< typename T >
inline int Test< T, 1 >::foo()
{
    return 1;
}

int main()
{
    Test< double, 2 > wTest2;
    Test< int, 1 > wTest1;
    wTest2.foo();
    wTest1.foo();
    return 0;
}
regu
  • 111
  • 3