I have a container object that is templatized. I am trying to make a specialized constructor for float
versions. P开发者_JS百科roblem is, when the compiler attempts to compile the second object that uses the float
version, I get a multiple definition of
error.
NOTES: The entire class in in the h
file. The file is wrapped with a definition (#ifndef
, #define
, and #endif
). g++ version 3.4.6. This compiles fine with other compilers, e.g. Intel's icc.
Code is similar to the following:
template <typename T>
class Container {
public:
Container();
virtual ~Container() {}
private:
std::vector<T> data;
// other members
};
template <> Container<float>::Container() {
// do something special
}
template <typename T> Container<T>::Container() {
// do default initialization
}
Any ideas? Thanks!
EDIT The objects being compiled are also going into separate shared objects, not sure if that has something to do with it.
Specializations still must abide by the one-definition rule just like any other non-template method. Either mark it inline or define the method body in a source file (not your header).
template <> Container<float>::Container() {
// do something special
}
is a definition of the specialisation. A specialisation has to be declared in every compilation unit it is used:
template <> Container<float>::Container();
and defined in only one of the CU. So your .h
has to have the declaration and you have to find an adequate (probably new) .cpp
for the definition. (As Mark B point out, making the specialization inline is also a way to allow to put the definition in all compilation unit where it is needed).
This is tricky. The problem is that your specialization is not a template, but an actual function definition. And since it's in a header, you get multiple definitions when you include it twice. Something like:
template<> Container<float>::Container();
in the header, and the implementation in a single source file.
you could use typeid
:
template <typename T> Container<T>::Container() {
if(typeid(T)==typeid(float)) {
// do something special
}
else {
// do default initialization
}
}
downside: you cant use initialization list for your special case. EDIT: When i wrote this answer, i still assumed that the error was caused by the compiler, not by the code of the OP (did not look into it that much). However this typeid approach is absolutely valid C++ (see link below), and its a quite nice workaround if templates indeed would not work correctly with your specific compiler, and it can easily be replaced by the template solution if once day you can switch to a better compiler.
demonstration: example @ ideone
精彩评论