views:

272

answers:

5

Hello everybody.
Lets say you have simple template function (not class member for the sake of simplicity) with type specific specialization in the same .h file...

template <class TYPE>
void    some_function(TYPE& val)
{
    // some generic implementation
}

template <>
inline void some_function<int>(int& val)
{
    // some int specific implementation
}

Unless you explicitly direct you compiler to inline the specialization (inline keyword) you will get linking error if .h file is included more than once (at least I do in Visual C++ 2008).
We all know that inline is just a suggestion to the compiler, which it can ignore. In this particular case is compiler allowed to ignore this suggestion and let linker to fail?

+6  A: 

If you don't use inline, then the same function gets compiled with extern linkage into multiple .obj files, which causes the linker to throw a duplicate symbol error.

This is independent of whether the compiler actually compiles your function inline, since it could treat it the same as a static function and make each implementation private to each compilation unit. However, you can't use static for this purpose since it means something else on member functions, so inline is your only choice.

Greg Hewgill
Thanks Greg. Am I correct to assume that inline is dual purpose keyword? And in case of template specialization the extern linkage is suppressed while function can still be inline or not?
BostonLogan
`inline` functions still have external linkage (3.5/3). The ODR does have a special case to allow one definition of them in each TU, however.
Roger Pate
@BostonLogan: it would really help if people stopped using phrases like "be inline". ;-) If a function has the inline keyword (or is implicitly inline like implicitly instantiated templates and member functions defined in a class definition), then in C++ terms it "is inline". Whether the compiler inlines a particular call to a function is not a property of the function, first because it's up to the compiler (perhaps taking inline status as a hint), and secondly because it can be true of some calls but not others.
Steve Jessop
A: 

I believe you can explicitly declare the method as extern and then put the specialization into a .cpp. I've tried something similar in a past life with GCC, but I don't recall the exact details of how it worked. MSDN Magazine has an article on this that might help.

James Schek
A: 

What you're actually seeing is the One Definition Rule (ODR) has a special case for inline functions, in that each TU may have a definition. If the function, such as your explicit int specialization, is not inline, then you will get multiple definition errors at link time. Such inline functions still have external linkage. Function templates are templates and so follow different rules. Instantiations/specializations of a function template are functions.

Using inline, as for any function, is just a hint, but you might want to apply it if the function is short (as for any function) or if you just want to keep it in the header. Here's an example without inline:

Header file:

template<class TYPE>
void some_function(TYPE& val) {
  // some generic implementation
}

template<>
void some_function<int>(int& val);

Implementation (.cpp) file:

template<>
void some_function<int>(int& val) {
  // some int specific implementation
}
Roger Pate
+1  A: 

This is defined by the standard and the compiler is totally compliant in this regard, from the looks of it. The linkage is all you are after. Implicit template instantiations have 'special' linkage, as inline functions do. There is also static (keyword), which has been deprecated in favor of anonymous namespaces:

namespace {
    …declarations…
}

So yes, this specialization (in your example) has the same linkage as:

void some_other_function(int& val) {
    // some int specific implementation
}

In fact, the compiler may mumble about inlining the specialization, in your example, saying they do not match. So it really is a best practice to label them both inline (or otherwise).

Justin
+2  A: 

You are misunderstanding the meaning of the often-mentioned "ignore inline" possibility.

No compiler is ever allowed to ignore the inline specifier used in function declaration and the consequences this specifier has with respect to One Definition Rule (ODR).

When someone says that compiler are allowed to "ignore inline", it only means that compilers are not required to actually inline the calls to the function in question. To "ignore inline" means to generate an ordinary (non-inlined) function call to an inline function.

In any case, even if the compiler decided to always generate ordinary calls to an inline function (i.e. to always "ignore inline"), it is still required to treat the function as inline for the purposes of ODR. How the compiler is going to do it is the problem of the compiler. You are not supposed to worry about it.

In your original example you should not not get any linker errors.

AndreyT
Thanks Andrey, this is what my question was about.
BostonLogan