VisualStudio C++ Linker problem with template classes
I still can't get it to work..
After I had to separate implementation from definition of one of my generic classes because of a forward declaration, i now get Linker errors when trying to build.
IShader.h:
template <typename ShadeType>
class IShader {
public:
template <typename T>
bool getProperty(const std::string& propertyName, ShaderProperty<T>** outProp);
};
so it's a generic class with a generic member function with a different generic开发者_运维问答 type
implementation looks like this:
#include "MRIShader.h"
template <typename ShadeType> template <typename T>
bool IShader<ShadeType>::getProperty(const std::string& propertyName, ShaderProperty<T>** outProp){
std::map<std::string, IShaderProperty* >::iterator i = m_shaderProperties.find(propertyName);
*outProp = NULL;
if( i != m_shaderProperties.end() ) {
*outProp = dynamic_cast<ShaderProperty<T>*>( i->second );
return true;
}
return false;
}
but i get Linker errors like this one:
error LNK2001: Nicht aufgelöstes externes Symbol ""public: bool __thiscall IShader<class A_Type>::getProperty<bool>(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class ShaderProperty<bool> * *)" (??$getProperty@_N@?$IShader@VA_Type@@@@QAE_NABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@PAPAV?$ShaderProperty@_N@@@Z)". SceneParser.obj
for bool, but also for many other types. I already read through this article: http://www.parashift.com/c++-faq-lite/templates.html
but adding
templace class IShader<bool>;
in the end of IShader.cpp doesn't solve the problem. I also tried to add the 'export' keyword before the keyword 'template' in the implementation, but this just gives me a syntax error.
What's the proper way to declare and implement my template class, which has templated member methods (with a different template type!) in separate files (.h and .cpp) without getting Linker errors?
thanks!
Your only providing a linkable object for the class in the translation unit, but the member function is templated on another parameter and has also to be explicitly specified.
I don't know if there is a more elegant way, but one compilable version would be:
template bool IShader<bool>::getProperty<bool>
(const std::string& propertyName,
ShaderProperty<bool>** outProp);
VC8 and GCC 3.4 both allow to leave out the <bool>
after the function name. I'm however not sure about the correct syntax in that case.
But as long as you're not having problems with the compilation time in a big project, save yourself the trouble and put the method definitions (marked inline) in a header.
If you're just worried about the size of the header file, move the definitions in another header file, e.g. IShaderImpl.h, that you include at the end of IShader.h.
Quick sample to remove doubts:
// IShader.h
template<typename T>
struct ShaderProperty {};
template <typename T>
class IShader {
public:
template <typename U>
void getProperty(ShaderProperty<U>**);
};
// IShader.cpp
#include <iostream>
#include "IShader.h"
template<typename T> template<typename U>
void IShader<T>::getProperty(ShaderProperty<U>**)
{ std::cout << "moo" << std::endl; }
template class IShader<bool>;
template void IShader<bool>::getProperty(ShaderProperty<bool>**);
// main.cpp
#include "IShader.h"
int main() {
IShader<bool> b;
ShaderProperty<bool>** p;
b.getProperty(p);
}
Templated classes in C++ must provide the declaration and implementation in the same file. Otherwise when another file includes the header, the linker won't be able to find the definition of those probably.
Did you include the cpp file from the header file?
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.13
Notice that foo-impl.cpp #includes a .cpp file, not a .h file. If that's confusing, click your heels twice, think of Kansas, and repeat after me, "I will do it anyway even though it's confusing." You can trust me on this one. But if you don't trust me or are simply curious,
EDIT I got this to compile:
//////////////////////////////////////////////////////////////////////////
// Foo.cpp - implementation of Foo
#include "stdafx.h"
template <typename ShadeType>
template <typename T>
bool IShader<ShadeType>::getProperty(ShaderProperty<T>** outProp){
*outProp = dynamic_cast<ShaderProperty<T>*>( NULL );
return false;
}
//////////////////////////////////////////////////////////////////////////
// Foo.h
template<typename T> class ShaderProperty
{
};
template <typename ShadeType>
class IShader {
public:
template <typename T>
bool getProperty(ShaderProperty<T>** outProp);
};
#include "Foo.cpp"
///Main.cpp
IShader<someclass> blah;
ShaderProperty<someclass2>* prop;
blah.getProperty(&prop);
So in other words you can't really hide your implementation code from the library users. You either have the code in the header file or include the cpp file WITH the header file.
精彩评论