flm*_*620 5 c++ dll templates lnk2005 visual-studio
我已经跟踪一个大型项目中的错误三天了,终于得到了一个最小的可重现示例。我想分享这个问题,并就 Visual Studio 的奇怪行为提出一些问题。
当您导出从实例化模板类继承的类时,例如
class __declspec(dllexport) classA : public Template<double>{}
Run Code Online (Sandbox Code Playgroud)
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)
}
Run Code Online (Sandbox Code Playgroud)
我在 VS2015 调试模式下编译代码,它给出了多重定义的错误
1>------ Build started: Project: AA, Configuration: Debug x64 ------
1> classA.cpp
1> AA.vcxproj -> D:\sandbox\build\aa\Debug\AA.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:\sandbox\build\Debug\Main.exe : fatal error LNK1169: one or more multiply defined symbols found
========== Build: 1 succeeded, 1 failed, 1 up-to-date, 0 skipped ==========
Run Code Online (Sandbox Code Playgroud)
如果我进行以下更改之一,则不会出现错误:
AA_APIat(2)并将链接模式更改为 STATIC at(1)(3)和取消评论(4)以及(5)(6)和取消评论(7)以及(8)/FORCE:MULTIPLE到项目 Main 的链接器为什么更改 1、2、3、4 和 5 有效?我觉得 3 和 4 可以工作真是太奇怪了。
如何在Visual Studio中正确解决这个问题?
我最近遇到了同样的问题。我最终成功解决了这个问题,所以我将分享我的知识。
问题根源:
该模板被实例化多次。那是因为您使用隐式实例化。一次当您声明类 AA_API classA 时,一次在 main 中当您声明 Template< double > a; 时 在主要。
这意味着您将拥有多个模板定义。
解决方案:
显式实例化。
// aa/template.h
#pragma once
template<class T>
class Template {
public:
Template() {}
};
template class Template<double>; // Put this line after your template class.
Run Code Online (Sandbox Code Playgroud)
注意:如果模板类在不同的项目中,则需要导出实例化。
我希望这能解决您的问题。它已经修复了我的。
| 归档时间: |
|
| 查看次数: |
1173 次 |
| 最近记录: |