tags:

views:

627

answers:

3

This is driving me mad for the past 1.5 hrs, I know it's a small thing but cannot find what's wrong (the fact that it's a rainy Friday afternoon, of course, does not help).

I have defined the following class that will hold configuration parameters read from a file and will let me access them from my program:

class VAConfig {
    friend std::ostream& operator<<( std::ostream& lhs, const VAConfig& rhs);

private:
    VAConfig();
    static std::string   configFilename;
    static VAConfig*     pConfigInstance;
    static TiXmlDocument*   pXmlDoc;
    std::map<std::string, std::string> valueHash;

public:
    static VAConfig* getInstance();
    static void setConfigFileName( std::string& filename ) { configFilename = filename; }
    virtual ~VAConfig();

    void readParameterSet( std::string parameterGroupName );
    template<typename T> T readParameter( const std::string parameterName );
    template<typename T> T convert( const std::string& value );
};

where the method convert() is defined in VAConfig.cpp as

template <typename T>
T VAConfig::convert( const std::string& value )
{
    T t;
    std::istringstream iss( value, std::istringstream::in );
    iss >> t;
    return t;
}

All quite simple. But when I test from my main program using

int y = parameters->convert<int>("5");

I get an "undefined reference to int VAConfig::convert<int>..." compilation error. Ditto for readParameter().

Looked at a lot of template tutorials but coul not figure this out. Any ideas?

Thanks, C

+5  A: 

If you move the implementation of the templated methods (convert and readParameter) to the header file, it should work.

The compiler must have access to the implementations of templated functions at the points where they're instantiated.

dominic hamon
+8  A: 

Templated code implementation should never be in a .cpp file: your compiler has to see them at the same time as it sees the code that calls them (unless you use explicit instantiation to generate the templated object code, but even then .cpp is the wrong file type to use).

What you need to do is move the implementation to either the header file, or to a file such as VAConfig.t.hpp, and then #include "VAConfig.t.hpp" whenever you use any templated member functions.

Seth Johnson
Thanks Seth and Dominic, I moved the implementations to teh header file and it worked. I never saw this aspect mentioned in any tutorial I read. So, why does the compiler need to see the implementation the same time it sees the code that calls them, i.e. what makes the templated fucntions unique in this regard?
recipriversexclusion
The compiler needs to have the entire template definition available when it instantiates it - so that it can substitute the template parameters and evaluate it.If your compiler supports it, you can declare your template as "extern" and use it the way you would any other member, at the cost of additional link-time work. GCC supports this as an extension. It's going to be part of the C++0x standard.
greyfade
A: 

A template method is merely a ... template for a method. The template arguments are to be filled in where the method is "instantiated".

It should be possible to build a compiler that is content with the declaration of a template method, and have a 'template compilation' step compile all the needed instances of the template method.

This is not the case for microsoft's vc. I heard a collegue mutter about it being the case on unix, though.

Most compilers instantiate the template method on request, where they are used in the source code. In order to instantiate the method, the compiler must 'see' the template function body. That's why the body is most often placed in either the header file, or in e.g. a .h.cpp file, which is then included as the last line of the .h file.

xtofl
What you're describing is an "extern template." It's included in the next version of the C++ standard and has been supported by GCC for a long time (as an extension). Visual C++ should support it in the current beta of the next release.
greyfade
@greyfade: Thanks!
xtofl