The reason why it doesn't work is that you are not instantiating your class template, neither are you instantiating your class template's constructor: while processing translation units (i.e. .cpp
files) other than lexer.cpp
that invoke that constructor, the compiler won't be able to see its definition, so it will not emit any object code for it; on the other hand, in the only translation unit that can see its definition (lexer.cpp
), you are not invoking the constructor, so again the compiler won't emit any object code.
As a result, no object code for your constructor is present in your program's compiled translation units, and the linker will complain about unresolved references to your class's constructor when trying to create the executable.
The extern
keyword is used to prevent the instantiation of a template in one translation unit (even though its full definition is visible!) when you know that it will be (explicitly) instantiated in another translation unit, thus saving compilation time. See this Q&A on StackOverflow for a clarification.
From Paragraph 14.7.2/2 of the C++11 Standard:
The syntax for explicit instantiation is:
explicit-instantiation:
extern(opt) template declaration
There are two forms of explicit instantiation: an explicit instantiation definition and an explicit instantiation declaration. An explicit instantiation declaration begins with the extern
keyword.
Thus, what you are providing is simply a declaration. There is no way of relegating member function definitions of a class template in a .cpp
file without getting unresolved reference errors from the linker, unless you instantiate them (possibly through an explicit instantiation of the class template) in that very same translation unit (the only one which has access to those definitions).
C++03 had a keyword called export
which allowed doing what you are trying to achieve, but it has been removed during standardization of C++11 because it proved to be too difficult to implement for compiler vendors.