C++ MSVC DLL导出从模板继承的类导致LNK2005已定义错误
我在一个大型项目中跟踪了一个错误3天,终于得到了一个最小可复制的示例。我想与大家分享这个问题,并就VisualStudio的怪异行为提出一些问题 导出从实例化模板类继承的类时,如C++ MSVC DLL导出从模板继承的类导致LNK2005已定义错误,c++,visual-studio,templates,dll,lnk2005,C++,Visual Studio,Templates,Dll,Lnk2005,我在一个大型项目中跟踪了一个错误3天,终于得到了一个最小可复制的示例。我想与大家分享这个问题,并就VisualStudio的怪异行为提出一些问题 导出从实例化模板类继承的类时,如 class_uudeclspec(dllexport)classA:公共模板{} MSVC还将在DLL中导出实例化的模板类template 如果使用者在其代码中包含“template.h”,然后实例化模板,同时链接到上述DLL,他将得到模板的两个定义,这将导致LNK2005和LNK1169错误。这一问题在本文中讨论
class_uudeclspec(dllexport)classA:公共模板{}
MSVC还将在DLL中导出实例化的模板类template
如果使用者在其代码中包含“template.h”
,然后实例化模板
,同时链接到上述DLL,他将得到模板
的两个定义,这将导致LNK2005和LNK1169错误。这一问题在本文中讨论
以下是此问题的最小可复制示例(完整代码为):
/--------------项目AA------------
//aa/CMakeLists.txt
cmake_最低要求(3.1版)
计划(机管局)
添加库(AA共享classA.cpp)/(1)
设置\u目标\u属性(AA属性编译\u标志“-DBUILD\u AA”)
//aa/config.h
#布拉格语一次
#ifdef_WIN32
#ifdef BUILD_AA
#定义AA_API___declspec(dllexport)
#否则
#定义AA_API___declspec(dllimport)
#恩迪夫
#否则
#定义AA_API
#恩迪夫
//aa/template.h
#布拉格语一次
模板
类模板{
公众:
模板(){}
};
//aa/classA.h
#布拉格语一次
#包括“config.h”
#包括“template.h”
AA_API类A:公共模板{//(2)
公众:
int fun();
};
//aa/classA.cpp
#包括“classA.h”
int classA::funA(){return 123;}
//--------工程主要部分----------
//CMakeLists.txt
cmake_最低要求(3.1版)
项目(主要)
集合(CMAKE_库_输出_目录${CMAKE_二进制_目录})
集合(CMAKE_运行时_输出_目录${CMAKE_二进制_目录})
添加_子目录(aa)
添加可执行文件(Main.cpp test.cpp)
目标链接图书馆(主要公共AA)
//main.cpp
#包括“aa/classA.h”
#包括
int main(){
模板a;/(3)
//A类aa;/(4)
//标准::cout classA.cpp
1> AA.vcxproj->D:\sandbox\build\AA\Debug\AA.dll
2> ----构建已启动:项目:主,配置:调试x64------
2> main.cpp
2> AA.lib(AA.dll):错误LNK2005:“public:u cdecl Template::Template(void)”(?0$Template@N@@QEAA@XZ)已在test.obj中定义
2> D:\sandbox\build\Debug\Main.exe:致命错误LNK1169:找到一个或多个多重定义符号
======生成:1个成功,1个失败,1个最新,0个已跳过==========
如果执行以下更改之一,则不会出现错误:
(2)
处移除AA_API
,并在(1)
(3)
和取消注释(4)
和(5)
(6)
和取消注释(7)
和(8)
/FORCE:MULTIPLE
中将项目参数更改为project Main的链接器如何在Visual Studio中正确解决此问题?我最近遇到了相同的问题。我最终设法解决了它,因此我将分享我的知识 问题来源: 该模板被多次实例化。这是因为您使用隐式实例化。一次在声明类AA_API classA时,一次在main中,一次在main中,一次在main中声明template
- 1,我不知道为什么它在发布模式下工作(考虑到我对模板缺乏深入的了解)
- 2,3,4,当您摆脱任何隐式模板实例化时,您就摆脱了多个定义
- 5,也许gcc的实例化方式不同,或者某个地方有一个强制乘法标志……我不知道
- 这并不能解决您的问题,它只是强制接受多个瞬间
// aa/template.h
#pragma once
template<class T>
class Template {
public:
Template() {}
};
template class Template<double>; // Put this line after your template class.
//aa/template.h
#布拉格语一次
模板
类模板{
公众:
模板(){}
};
模板类template;//将此行放在模板类之后。
注意:如果模板类位于不同的项目中,则需要导出实例化
我希望这能解决你的问题。它解决了我的问题。谢谢你的分享。但是头文件中的显式实例化并不能解决我的问题。如果多个cpp中包含
template.h
,将有多个定义。如果我在头文件中添加此显式实例化,步骤4将不再解决我的问题。是的,它将解决我的问题好的,你的问题的性质略有不同。不幸的是,我不知道确切的解释,但是如果我用它生成的默认构造函数替换你模板类中的构造函数。你甚至不需要任何显式实例化。这个问题是否曾向microsoft报告过?看起来是一个非常可怕的问题,没有什么好结果粘连。
// aa/template.h
#pragma once
template<class T>
class Template {
public:
Template() {}
};
template class Template<double>; // Put this line after your template class.