2017-05-08 91 views
2

雖然試圖複製在Visual Studio 2017年在此question行爲我發現,而不是鏈接&FuncTemplate<C>完全相同的地址功能template<> FuncTemplate<C>() {}被複制到DLLA和dllB從而使相應的測試程序總是返回not equalMSVC 2017年創建模板功能的拷貝共享庫

該解決方案設置爲3個Win32Projects,其中一個爲ConsoleApplication,其他爲DLL。爲了鏈接DLL,我將它們添加爲控制檯項目的引用(手動鏈接也不起作用)。我所做的代碼中唯一的變化是將__declspec(dllexport)添加到a()b()

這是行爲標準嗎?似乎應該在這裏使用ODR來摺疊該函數的副本。有沒有辦法在另一個問題中看到同樣的行爲?

Template.h

#pragma once 

typedef void (*FuncPtr)(); 

template<typename T> 
void FuncTemplate() {} 

class C {}; 

a.cpp - dll項目1

#include "Template.h" 

__declspec(dllexport) FuncPtr a() { 
    return &FuncTemplate<C>; 
} 

b.cpp - dll項目2

#include "Template.h" 

__declspec(dllexport)FuncPtr b() { 
    return &FuncTemplate<C>; 
} 

的main.cpp - 控制檯項目

#include <iostream> 

#include "i.h" 

// seems like there is no __declspec(dllimport) needed here 
FuncPtr a(); 
FuncPtr b(); 

int main() { 
    std::cout << (a() == b() ? "equal" : "not equal") << std::endl; 

    return 0; 
} 
+0

該標準不包括DLL –

回答

0

C++編譯一般分爲兩個部分,編譯器本身和連接器。連接器的工作是將所有相同功能的彙編整合到一個單元中,並丟棄重複項。在鏈接步驟結束時,每個函數都應該是鏈接器輸出的一部分,或者標記爲需要在另一個DLL的執行時解析。每個DLL將包含該函數的副本,如果該DLL正在該DLL中使用或從中導出。

在執行時解析動態鏈接的過程不在C++工具鏈中,它發生在OS級別。它沒有像鏈接器那樣整合重複的功能。

我認爲就ODR而言,每個DLL都被認爲是一個單獨的可執行文件。

+0

所以它只是gcc做與msvc不同的東西呢?任何機會在msvc中獲得相同的行爲? – mailgerigk

+0

@mailgerigk你的問題沒有提到gcc,我沒有資格回答。正如我所說的,動態鏈接是在操作系統控制下進行的,而不是編譯器 - 它將取決於您的操作系統內置的功能。 –