Visual Studio C ++与模板类的链接器问题

时间:2009-12-16 03:22:15

标签: c++ templates linker

我仍然无法让它发挥作用..

由于前向声明,我不得不将实现与我的一个泛型类的定义分开,我现在在尝试构建时遇到链接器错误。

IShader.h:

template <typename ShadeType> 
class IShader {

public:
template <typename T>
bool getProperty(const std::string& propertyName, ShaderProperty<T>** outProp);
};

所以它是一个泛型类,具有通用成员函数,具有不同的泛型类型

实现如下:

#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;
}

但是我得到像这样的链接器错误:

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

对于bool,但也适用于许多其他类型。 我已经阅读了这篇文章: http://www.parashift.com/c++-faq-lite/templates.html

但添加

templace class IShader<bool>;
在IShader.cpp的最后

没有解决问题。 我还尝试在实现中的关键字“template”之前添加'export'关键字,但这只是给我一个语法错误。

声明和实现我的模板类的正确方法是什么,模板类在单独的文件(.h和.cpp)中具有模板化成员方法(具有不同的模板类型!)而不会出现链接器错误?

谢谢!

3 个答案:

答案 0 :(得分:2)

您只在翻译单元中为类提供可链接对象,但成员函数是在另一个参数上模板化的,并且还必须明确指定。

我不知道是否有更优雅的方式,但一个可编辑的版本将是:

template bool IShader<bool>::getProperty<bool>
                 (const std::string& propertyName, 
                  ShaderProperty<bool>** outProp);

VC8和GCC 3.4都允许在函数名后省略<bool>。但是我不确定那种情况下的正确语法。

但只要您在大型项目中没有编译时间问题,请省去麻烦并将方法定义(标记为内联)放在标题中。
如果您只是担心头文件的大小,请将定义移到另一个头文件中,例如 IShaderImpl.h ,包含在 IShader.h 的末尾。

快速取样以消除疑虑:

// 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);
}

答案 1 :(得分:0)

您是否在头文件中包含了cpp文件?

http://www.parashift.com/c++-faq-lite/templates.html#faq-35.13

  

请注意foo-impl.cpp #includes a   .cpp文件,而不是.h文件。如果那样的话   令人困惑,点击你的高跟鞋两次,   想到堪萨斯,并在我之后重复,   “尽管如此,我仍会这样做   令人困惑的。“你可以相信我   一。但如果你不相信我或是   简直好奇,

编辑我得到了这个编译:

//////////////////////////////////////////////////////////////////////////
// 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);

所以换句话说,你无法真正隐藏库用户的实现代码。您可以在头文件中包含代码,也可以在头文件中包含cpp文件。

答案 2 :(得分:0)

C ++中的模板化类必须在同一文件中提供声明和实现。否则当另一个文件包含头时,链接器将无法找到那些可能的定义。