for quite some time i struggle with old-as-c++ problem of separating the implementation of a templated function from the definition. C++0x' extern
seem to be a solution for this, but i fail to apply it properly
my code:
main.cpp
#include <iostream>
#include <string>
#include "lexer.h"
int main(int argc, char const *argv[]) {
std::string foo("foo");
new lexer((foo.begin()),(foo.end()));
return 0;
}
lexer.h
#ifndef lexer_h
#define lexer_h
class lexer {
public:
extern template<class InputIterator>
lexer(InputIterator i, InputIterator end);
};
#endif //lexer_h
lexer.cpp
#include "lexer.h"
template<class InputIterator >
lexer::lexer(InputIterator i, InputIterator end) {
//make it work
};
compiling with g++ main.cpp lexer.cpp -std=c++0x
. I want to use object files later.
so how would it look fixed?
Unless you know the complete set of types used as arguments to InputIterator
, the definition needs to go into the header file.
A template definition (implementation) can only be separated from the declaration when you know the full set of instantiations (arguments) needed. The compiler cannot remember what instantiations were used in one .cpp
(translation unit) and provide them using code in another .cpp
.
As Andy mentions, the behavior you seem to be looking for was previously assigned to the C++03 export
keyword, which was seldom implemented, and turned out to be less useful than hoped, and has now been completely removed from the standard.
If you do want to go this route (I'm writing a similar library right now!), the extern
keyword needs to go outside the class {}
scope and the .cpp
file needs to explicitly instantiate the needed specializations.
// header file
class lexer {
public:
template<class InputIterator>
lexer(InputIterator i, InputIterator end);
};
extern template lexer::lexer( foo::iterator, foo::iterator );
extern template lexer::lexer( bar::iterator, bar::iterator );
// source file
template<class InputIterator >
lexer::lexer(InputIterator i, InputIterator end) {
//make it work
};
template lexer::lexer( foo::iterator, foo::iterator );
template lexer::lexer( bar::iterator, bar::iterator );
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 (ie .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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.