Ich habe einen Fehler in einem großen Projekt für 3 Tage verfolgt und schließlich ein Minimum reproduzierbar Beispiel erhalten. Ich möchte dieses Problem teilen und einige Fragen zum seltsamen Verhalten von Visual Studio stellen.MSVC DLL exportierende Klasse, die von Vorlage erbt Ursache LNK2005 bereits definierten Fehler
Wenn Sie eine Klasse exportieren, die von einer instanziierten Template-Klasse erbt, wie
class __declspec(dllexport) classA : public Template<double>{}
MSVC wird exportiert auch die instanziiert Template-Klasse Template<double>
in DLL.
Wenn die Verbraucher "template.h"
in seinem Code enthalten dann ein Template<double>
, instanziiert zugleich, Link zu dem oben DLL QND, wird er zwei Definition von Template<double>
, erhält die LNK2005 und LNK1169 Fehler verursacht. Dieses Problem wird in Microsoft DLL export and C++ templates diskutiert.
ist hier ein Minimum reproduzierbares Beispiel für dieses Problem (Full-Code ist here):
// ----------- 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)
}
ich den Code in VS2015 Debug-Modus kompilieren, gibt sie mehrfach Fehler definiert
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)" ([email protected]@@[email protected]) 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 ==========
Wenn ich tun ONE OF die folgenden Änderungen, wird es keinen Fehler geben:
- Änderungsmodus bei
(1)
- Kommentar
(3)
und uncomment(4)
und(5)
- Kommentar
(6)
und uncomment(7)
und(8)
- Compile in Linux von gcc
- entfernen
AA_API
bei(2)
und ändern Link-Modus STATIC Release - Projektparameter in VS ändern:
/FORCE:MULTIPLE
zum Linker für Projekt Main hinzufügen
Frage:
Warum Änderungen 1,2,3,4 und 5 arbeiten? Ich finde es komisch, dass 3 und 4 funktionieren können.
Wie kann dieses Problem in Visual Studio ordnungsgemäß gelöst werden?
Vielen Dank für das Teilen. Aber die explizite Instanziierung in der Header-Datei löst mein Problem nicht. Wenn "template.h" in mehreren cpp enthalten ist, gibt es mehrere Definitionen. – flm8620
Wenn ich diese explizite Instanziierung in Header-Datei hinzufüge, löst Schritt 4 nicht mehr mein Problem. – flm8620
Ja, es sieht so aus, als ob die Art Ihres Problems etwas anders ist. Leider kenne ich die genaue Erklärung nicht, aber wenn ich den Konstruktor in Ihrer Template-Klasse durch den Standardkonstruktor ersetze, den er erstellt. Sie brauchen nicht einmal eine explizite Instanziierung. –