Wednesday, October 25, 2006

Specialised Function Template Linking Problem (Multiple Definition)

Imagine a scenario where you have this specialised template implementation, where it converts the first argument to string and place it on second argument. It also indicates the conversion is successful or not.

template< typename T >
bool convertToString(T x, std::string& result)
{
...
}

// As there's no point of converting a string to another string
template<>
bool convertToString(std::string x, std::string& result)
{
...
}

There're perfectly nothing wrong with that when you're using this function template within your class, i.e.
string a_string, out;
f< std::string >(a_string, out));
f(a_string, out); // this will also trigger the specialised template function

However, in most cases, you'll be using these templates on other classes by #include-ing it. All of a sudden, it gives you an error message "Linked error in function XXX: multiple definition of `bool convertToString ... at line YYY". (this error message has been polished for your readability)

Now you're scratching your head, and ask what've gone wrong here? Fret not, take a step back, all the reasoning behind it is that the compiler linker can't decide on which one to choose as both functions DO support std::string. From outside word, this so-called smart tempate functions library just have two SAME functions with the same number argument and the same return type. We need to tell this picky compiler on which one he should be using.

Enough the description, all we need to do is just inlining the specialised template, which essentially tell the compiler that this should be the one you should looked at if it there's multiple definition for it, i.e.

template<>
inline bool convertToString(std::string x, std::string& out)
{
...
}

Problems gone!

4 comments:

High Power Rocketry said...

: )

metao! said...

If your implementation is in fact of a convertToString() function, one would wonder why lexical_cast is not good enough?

Andy Tjuatja said...

Well, convertToString is just merely name...I am fully aware that lexical_cast can perform the task.

The real code I'm experiencing involves parsing a string into vector of elements (i.e. int, double, etc) based on a delimiter.

Clearly there's no point of lexical_cast(ing) a substring into another string. (Not that it'll harm anyone though, I'm just being picky here)

Just ignore the "non-descriptive enough" function name =)

Unknown said...

Actually, what's happening is this:

Consider that your template function (and the specialization) are in template.h

Now consider that you #include this in both a.cpp and b.cpp and that they are both compiled into seperate objects (a.o and b.o).

Right... now when you link a.o and b.o into your mainline, the linker will barf.

It barfs because the specialized template function is a proper function, not a template function. a.obj and b.obj contain duplicate definitions of it because they both #included the header in which it was defined.

Like you said, you can resolve this using inline, or even static or extern.