从模板继承的 MSVC DLL 导出类会导致LNK2005已定义的错误
MSVC DLL exporting class that inherits from template cause LNK2005 already defined error
我已经在一个大型项目中跟踪了一个错误 3 天,终于得到了一个最小的可重现示例。我想分享这个问题,并就Visual Studio的奇怪行为提出一些问题。
当您导出从实例化模板类继承的类时,例如
class __declspec(dllexport) classA : public Template<double>{}
MSVC 还将导出实例化的模板类Template<double>
DLL。
如果消费者在他的代码中包含"template.h"
然后实例化一个Template<double>
,同时qnd链接到上面的DLL,他将得到两个Template<double>
定义,这会导致LNK2005和LNK1169错误。Microsoft DLL 导出和C++模板中讨论了此问题。
这是此问题的最小可重现示例(完整代码在这里(:
// ----------- Project AA ------------
// aa/CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(AA)
add_library(AA SHARED classA.cpp) //(1)
set_target_properties(AA PROPERTIES COMPILE_FLAGS "-DBUILD_AA")
// aa/config.h
#pragma once
#ifdef _WIN32
# ifdef BUILD_AA
# define AA_API __declspec( dllexport )
# else
# define AA_API __declspec( dllimport )
# endif
#else
# define AA_API
#endif
// aa/template.h
#pragma once
template<class T>
class Template {
public:
Template() {}
};
// aa/classA.h
#pragma once
#include "config.h"
#include "template.h"
class AA_API classA : public Template<double> { //(2)
public:
int fun();
};
// aa/classA.cpp
#include "classA.h"
int classA::funA(){return 123;}
// ----------- Project Main ----------
//CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(Main)
set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
add_subdirectory(aa)
add_executable(Main main.cpp test.cpp)
target_link_libraries(Main PUBLIC AA)
// main.cpp
#include "aa/classA.h"
#include <iostream>
int main(){
Template<double> a; //(3)
//classA aa; //(4)
//std::cout << aa.funA() << std::endl; //(5)
return 0;
}
// test.cpp
#include "aa/template.h"
class classB {
Template<double> t;
};
class classC : public Template<double> {};
void fun() {
Template<double> b; //(6)
//class classB; //(7)
//class classC; //(8)
}
我在VS2015调试模式下编译代码,它给出了多重定义的错误
1>------ Build started: Project: AA, Configuration: Debug x64 ------
1> classA.cpp
1> AA.vcxproj -> D:sandboxbuildaaDebugAA.dll
2>------ Build started: Project: Main, Configuration: Debug x64 ------
2> main.cpp
2>AA.lib(AA.dll) : error LNK2005: "public: __cdecl Template<double>::Template<double>(void)" (??0?$Template@N@@QEAA@XZ) already defined in test.obj
2>D:sandboxbuildDebugMain.exe : fatal error LNK1169: one or more multiply defined symbols found
========== Build: 1 succeeded, 1 failed, 1 up-to-date, 0 skipped ==========
如果我执行以下更改之一,则不会有错误:
- 更改为发布模式
- 在
(2)
时删除AA_API
,并将链接模式更改为 STATIC at(1)
(3)
注释和取消注释(4)
和(5)
(6)
注释和取消注释(7)
和(8)
- 通过 gcc 在 Linux 中编译
- 在VS中更改项目参数:将
/FORCE:MULTIPLE
添加到项目主的链接器
问题:
为什么更改 1、2、3、4 和 5 有效?我觉得 3 和 4 可以工作太奇怪了。
如何在视觉工作室中正确解决此问题?
我最近遇到了同样的问题。我终于设法修复了它,所以我将分享我的知识。
问题来源:
模板会实例化多次。这是因为您使用隐式实例化。当您声明类 AA_API类 A 时一次,当您声明模板时在主<双>a;在主要。双>
这意味着您将有多个模板定义。
- 1,我不确定为什么它在发布模式下工作(考虑到我对模板缺乏深入了解(
- 2,3,4,当你摆脱任何隐式模板实例化时,你摆脱了多个定义
- 5,也许 GCC 以不同的方式进行实例化,或者某处有一个力乘法标志......我不知道
- 6,这并不能解决你的问题,它只是迫使接受多个瞬间。
溶液:
显式实例化。
// aa/template.h
#pragma once
template<class T>
class Template {
public:
Template() {}
};
template class Template<double>; // Put this line after your template class.
注意:如果模板类位于其他项目中,则需要导出实例化。
我希望这能解决你的问题。它修复了我的。
相关文章:
- 运行 C++ 单元测试时LNK2005链接错误
- 无法使函数公开。获取:"LNK2005"错误。如何调试链接器错误
- 在UE4(虚幻引擎4)中集成LuaJit时LNK2005错误
- 我在用c ++编程时一直遇到LNK2005错误,我似乎无法弄清楚问题是什么
- C++中的即时对象初始化失败,出现LNK2005错误
- LNK2005错误,有多个翻译单元
- LNK2005错误通过在 .cpp 而不是标头中定义来解决.为什么
- 链接器LNK2005错误
- C++标头不能包含LNK2005错误
- LNK2005错误,已定义:可能有一个定义规则违反
- 每个.cpp创建两个LNK2005错误
- C++ lnk2005 错误在两个带有外部"C"的文件上,为什么?
- LNK2005错误,已在main.obj中定义
- 将开发环境从Visual Studio 2003移植到2010:为什么我会收到LNK2005错误
- 为什么LNK2005错误消失
- 链接使用boost的多个项目时发生LNK2005错误
- 当从DLL导出STL std::basic_string模板时,我得到一个LNK2005错误
- 包括头文件和.cpp文件到主.cpp文件LNK2005错误已经在对象中定义
- 使链接增强.LNK2005错误
- LNK2005错误.看起来一个文件被包含了两次