40
votes

The following code:

template <typename S, typename T>
struct foo {
   void bar();
};

template <typename T>
void foo <int, T>::bar() {
}

gives me the error

invalid use of incomplete type 'struct foo<int, T>'
declaration of 'struct foo<int, T>'

(I'm using gcc.) Is my syntax for partial specialization wrong? Note that if I remove the second argument:

template <typename S>
struct foo {
   void bar();
};

template <>
void foo <int>::bar() {
}

then it compiles correctly.

5

5 Answers

44
votes

You can't partially specialize a function. If you wish to do so on a member function, you must partially specialize the entire template (yes, it's irritating). On a large templated class, to partially specialize a function, you would need a workaround. Perhaps a templated member struct (e.g. template <typename U = T> struct Nested) would work. Or else you can try deriving from another template that partially specializes (works if you use the this->member notation, otherwise you will encounter compiler errors).

8
votes

Although coppro mentioned two solutions already and Anonymous explained the second one, it took me quite some time to understand the first one. Maybe the following code is helpful for someone stumbling across this site, which still ranks high in google, like me. The example (passing a vector/array/single element of numericalT as dataT and then accessing it via [] or directly) is of course somewhat contrived, but should illustrate how you actually can come very close to partially specializing a member function by wrapping it in a partially specialized class.

/* The following circumvents the impossible partial specialization of 
a member function 
actualClass<dataT,numericalT,1>::access
as well as the non-nonsensical full specialisation of the possibly
very big actualClass. */

//helper:
template <typename dataT, typename numericalT, unsigned int dataDim>
class specialised{
public:
  numericalT& access(dataT& x, const unsigned int index){return x[index];}
};

//partial specialisation:
template <typename dataT, typename numericalT>
class specialised<dataT,numericalT,1>{
public:
  numericalT& access(dataT& x, const unsigned int index){return x;}
};

//your actual class:
template <typename dataT, typename numericalT, unsigned int dataDim>
class actualClass{
private:
  dataT x;
  specialised<dataT,numericalT,dataDim> accessor;
public:
  //... for(int i=0;i<dataDim;++i) ...accessor.access(x,i) ...
};
5
votes

If you need to partially specialise a constructor, you might try something like:

template <class T, int N>
struct thingBase
{
    //Data members and other stuff.
};

template <class T, int N> struct thing : thingBase<T, N> {};

template <class T> struct thing<T, 42> : thingBase<T, 42>
{
    thing(T * param1, wchar_t * param2)
    {
        //Special construction if N equals 42.
    }
};

Note: this was anonymised from something I'm working on. You can also use this when you have a template class with lots and lots of members and you just want to add a function.

1
votes

If you're reading this question then you might like to be reminded that although you can't partially specialise methods you can add a non-templated overload, which will be called in preference to the templated function. i.e.

struct A
{
  template<typename T>
  bool foo(T arg) { return true; }

  bool foo(int arg) { return false; }

  void bar()
  {
    bool test = foo(7);  // Returns false
  }
};
1
votes

In C++ 17, I use "if constexpr" to avoid specialize (and rewrite) my method. For example :

template <size_t TSize>
struct A
{
    void recursiveMethod();
};

template <size_t TSize>
void A<TSize>::recursiveMethod()
{
    if constexpr (TSize == 1)
    {
        //[...] imple without subA
    }
    else
    {
        A<TSize - 1> subA;

        //[...] imple
    }
}

That avoid to specialize A<1>::recursiveMethod(). You can also use this method for type like this example :

template <typename T>
struct A
{
    void foo();
};

template <typename T>
void A<T>::foo()
{
    if constexpr (std::is_arithmetic_v<T>)
    {
        std::cout << "arithmetic" << std::endl;
    }
    else
    {
        std::cout << "other" << std::endl;
    }
}


int main()
{
    A<char*> a;
    a.foo();

    A<int> b;

    b.foo();
}

output :

other
arithmetic