Reputation: 78595
Note: the following code is illegal, but a conforming compiler is not required to reject it (and some don't).
In a library I'm working with I have a template function declaration for Foo
and a template function definition for Bar
in foobar.h
:
template<class C> int Foo();
template<class C> int Bar() {
return Something( Foo<C>() );
}
The intent is that other code would be able to use it like this:
#include "foobar.h"
int main() {
Bar<MyClass>();
return 0;
}
// Ideally, the usage (above) and the definition (below)
// would/could be in different translation units.
template<> int Foo<MyClass>() { return 5; }
The question: Is there a way to make this work that is also legal?
The issue is (if I'm understanding things correctly) that despite compiling, this is technically illegal: it violates the ODR because both the explicit specialization and the usage of Bar<MyClass>
count as definitions, despite the fact that there is no body to work with in the usage case.
The reasons I want to use this pattern to parameterize Foo
is that, as a result of the style guide I'm required to follow, the only way to ensure that anything is lexically included before the definition of Bar
is for it to be included by foobar.h
. But (for reason I expect I don't need to explain) that's a non-starter.
Upvotes: 2
Views: 286
Reputation: 14212
Is there a way to make this work that is also legal?
Yes, declare the specialization before it is used. Simply swapping the order of the specialization and main in your file would do this in the example you provided. However, in the example, you would still have to make sure no other TU used the specialization without declaring it.
Generally these specializations should be declared in a header.
Within what appear to be the confines of your example (i.e. no radical changes), there is no other way to make this work.
Upvotes: 3
Reputation: 39374
This compiles links and runs with both VS2008 and gcc 4.5.2:
template<class C> int Foo();
int Something(int i ){ return i; }
template<class C> int Bar() {
return Something( Foo<C>() );
}
class MyClass{};
class FooClass{};
// Update:
// Declaration of a specialisation.
template<> int Foo<MyClass>();
int Zoo(){
return Something( Foo<MyClass>() );
}
#include <iostream>
int main() {
std::cout << Bar<MyClass>() << std::endl;
std::cout << Zoo() << std::endl;
std::cout << Bar<FooClass>() << std::endl;
return 0;
}
// Definitions of specialisations.
template<> int Foo<MyClass>() { return 5; }
template<> int Foo<FooClass>() { return 6; }
The output is:
5
5
6
The reason this works is that despite only being declared, template function Foo
does have the two required definitions available to the linker.
At compile time, when the compiler sees the definition of main
, it can create specialisations of Bar
, but cannot create specialisations of Foo
. In this case it just creates function calls to Foo<MyClass>()
and Foo<FooClass>()
.
Later on the compiler finds specialisations of Foo
which it compiles, leaves in the object file, but does nothing else with at the time. When the linker runs it finds everything it needs.
Update:
So I don't know why this is illegal, but for some reason it does seems to compile and run.
Upvotes: 1
Reputation: 64223
It is not legal, since it is not possible to specialize template functions.
You could do something like this :
template< typename T >
struct foo
{
static int doSomething() {return 0;}
};
template< >
struct foo<int>
{
static int doSomething() {return 5;}
};
Upvotes: 1