I specialized a template and encountered a different beahviour between the MSVC compiler and MinGW/GCC. Here is the header file:
// MyClass.h
#ifndef MYCLASS_HEADER
#define MYCLASS_HEADER
template<typename T>
class MyClass {
public:
virtual void doSomething() {
// some code
}
};
// specialization prototype here
#endif
Now, the difference. To avoid multiple definitions, i specialized only a prototype in the header file, the implementation is in a cpp file. The specialization is the problem. the GCC/MinGW compiler accepts only this one:
template<> void MyClass<int>::doSomething(); // GCC version
And MSVC only this:
extern template void MyClass<int>::doSomething(); // MSVC version
The implementation in the CPP file is the same for both:
// MyClass.cpp
#include "MyClass.h"
template<> void MyClass<int>::doSomething() {
// some code
}
with the GCC prototype the MSVC compiler throws an "unresolved external symbol" error, GCC with the MSVC version throws "specialization of ... after instantiation".
At the moment, i have the workaround:
#ifdef _MSC_VER
extern template
#else
template<>
#endif
void MyClass<int>::doSomething();
in the header file. It works, but i don't like it. Is there a way to avoid the compiler specific switch?
These are not the same thing:
template<> void MyClass<int>::doSomething(); // GCC version
extern template void MyClass<int>::doSomething(); // MSVC version
The first one declares an explicit specialization, the second one declares an explicit instantiation.
with the GCC prototype the MSVC compiler throws an "unresolved external symbol" error, GCC with the MSVC version throws "specialization of ... after instantiation".
The GCC error is telling you that there has been an implicit instantiation of MyClass<int>::doSomething()
earlier in the file than the declaration of the explicit specialization; that is a bug in your code. You must declare the explicit specialization before any use of it that causes an implicit instantiation, otherwise that implicit instantiation will use the primary template definition, not the specialization. You can usually ensure that the specialization is declared before it's used by declaring it directly after the definition of the primary template, before any instantiations of MyClass<int>
.
I don't know why you get the MSVC error, it sounds as though you are failing to link to MyClass.cpp
. If that's not it, you could try adding an explicit instantiation definition to MyClass.cpp
to force the symbol to be emitted in that file:
template void MyClass<int>::doSomething(); // N.B. no "extern" on definition
Have you tried declaring both the specialization and instantiation, but ensuring they are declared before any implicit instantiations? That should be valid C++ e.g.
#ifndef MYCLASS_H
#define MYCLASS_H
template<typename T>
class MyClass {
public:
virtual void doSomething() {
// some code
}
};
// declare explicit specialization
template<> void MyClass<int>::doSomething();
// declare explicit instantiation
extern template void MyClass<int>::doSomething();
#endif
.
// MyClass.cpp
#include "MyClass.h"
// define explicit specialization
template<> void MyClass<int>::doSomething() {
// some code
}
// define explicit instantiation
template void MyClass<int>::doSomething();
Alternatively, if you can't make that work with both compilers, you could put the definition of the specialized member function in the header and declare it inline
, which would also avoid multiple definition errors.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With