Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/visual-studio/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ MSVC DLL导出从模板继承的类导致LNK2005已定义错误_C++_Visual Studio_Templates_Dll_Lnk2005 - Fatal编程技术网

C++ MSVC DLL导出从模板继承的类导致LNK2005已定义错误

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错误。这一问题在本文中讨论

我在一个大型项目中跟踪了一个错误3天,终于得到了一个最小可复制的示例。我想与大家分享这个问题,并就VisualStudio的怪异行为提出一些问题

导出从实例化模板类继承的类时,如

class_uudeclspec(dllexport)classA:公共模板{}
MSVC还将在DLL中导出实例化的模板类
template

如果使用者在其代码中包含
“template.h”
,然后实例化
模板
,同时链接到上述DLL,他将得到
模板
的两个定义,这将导致LNK2005LNK1169错误。这一问题在本文中讨论

以下是此问题的最小可复制示例(完整代码为):

/--------------项目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)
  • 用gcc在Linux下编译
  • 在VS:add
    /FORCE:MULTIPLE
    中将项目参数更改为project Main的链接器
  • 问题: 为什么改变1,2,3,4和5会起作用?我觉得3和4能起作用是很奇怪的


    如何在Visual Studio中正确解决此问题?

    我最近遇到了相同的问题。我最终设法解决了它,因此我将分享我的知识

    问题来源:

    该模板被多次实例化。这是因为您使用隐式实例化。一次在声明类AA_API classA时,一次在main中,一次在main中,一次在main中声明templatea

    这意味着您将有多个模板定义

    • 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.