"invalid use of incomplete type" error with partial template specialization

Viewed 23894

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 Answers

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).

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
  }
};

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
Related