0

I am stuck with this code and don't understand the error. I'm trying to make a forward declaration of template specialization in a header and then define this specialization in a source file. When I try to include this header, compiler complains that I'm using incomplete type.

Error: $ error: invalid use of incomplete type 'A_Template<Stub *>' std::cout << A_Template<Stub*>().int_method() << std::endl; ^~~~~~~~~~~~~~~~~~~ $ note: forward declaration of 'A_Template<Stub *>' struct A_Template<Stub*>; ^

/* a.h */
#pragma once
template <class T>
struct A_Template{};

class Stub{};

template<>
struct A_Template<Stub*>;


/* a.cpp */
#include "a.h"

template<>
struct A_Template<Stub*> {
    int int_method() {return 42;}
};


/* main.cpp */
#include <iostream>
#include "a.h"

int main() {    
    std::cout << A_Template<Stub*>().int_method();
    return 0;
}

Can anyone tell me what is wrong and is there a way to fix it?

antonpp
  • 2,333
  • 23
  • 28

1 Answers1

4

This is the exact same problem you would have trying to put the definition of any class/struct in a source file, independent of the template stuff. A class type is incomplete any time its definition has not been previously seen in the same translation unit, and an incomplete class type can't be used in much of any way other than passing around pointers and references to that type.

So the #include "a.h" brings in the declaration of A_Template<Stub*>, but no definition for it, so your expression using it is illegal. Basically, without seeing the definition, the compiler has no way of knowing:

  • how much storage is needed for an A_Template<Stub*> object of that type,
  • whether the default constructor call A_Template<Stub*>() is valid,
  • if it is valid, the signature of the constructor (which might be a plain constructor with no parameters, a constructor with some defaulted parameters, or a template constructor),
  • whether the .int_method member access is valid,
  • if it is valid, whether int_method names a member function or names an object which might be a function pointer or a class type with an operator(),
  • if int_method is a member function, the signature of the member function, just as with the constructor, or
  • whether the implicit destructor call for the temporary A_Template<Stub*> is valid.

The definition of a class template explicit or partial specialization generally needs to be in the header file, just like any other class definition. But it's fine to forward-declare it and define it later when necessary.

aschepler
  • 70,891
  • 9
  • 107
  • 161
  • Oh, thanks! I was misled by the fact that it's possible to put apart function declaration/definition and was expecting something similar with classes. I guess, the key point here is that with functions it can be done on linking phase and with types it's compiler's duty. – antonpp Jan 20 '18 at 00:14