2017-02-28 40 views
1

我遇到的情況,我不知道它是否可以考慮在代碼中的編譯器/連接或某些/誤用一個錯誤,一個錯誤會影響不同的翻譯單元誤解C++標準。局部結構通過使用通用模板功能的

兩個不同的源文件(包含實際代碼中的單元測試)聲明一個具有相同名稱但略有不同的成員的結構。兩個源文件都引用一個頭文件,該頭文件包含一個模板化的輔助方法,並返回模板的一個向量(以真實代碼執行反序列化)。

編譯完成後沒有任何錯誤或警告,我意識到該模板只針對一種類型,並在兩個翻譯單元中使用(儘管類型在.cpp文件中聲明),導致錯誤的結果。

下面是概念的一個簡短證明:

Main.cpp的

#include <iostream> 
#include <string> 

#include "Header.h" 

struct Foo 
{ 
    std::string name = "FooMain"; 
}; 

void test1() 
{ 
    auto v = getVector<Foo>(); 
    std::cout << v[0].name << ' ' 
       << v[1].name << '\n'; 
} 

void test2(); 

int main() 
{ 
    test1(); 
    test2(); 
} 

Second.cpp

#include <iostream> 
#include <string> 

#include "Header.h" 

struct Foo 
{ 
    std::string name = "FooSecond"; 
    int extraInfo = 1; 
}; 

void test2() 
{ 
    auto v = getVector<Foo>(); 
    std::cout << v[0].name << ' ' << v[0].extraInfo << ' ' 
       << v[1].name << ' ' << v[1].extraInfo << '\n'; 
} 

Header.h

#ifndef _HEADER_H_ 
#define _HEADER_H_ 

#include <vector> 

template<typename T> 
auto getVector() 
{ 
    std::vector<T> result; 

    result.push_back({}); 
    result.push_back({}); 

    return result; 
} 

#endif 

輸出是(每一次數字是不同的),兩者的Visual Studio 2015年和gcc 4.9.2下(32位Windows)中

FooMain FooMain 
FooMain 1299148614 FooMain 1097202845 

註釋掉test1()使代碼test2()返回預計產量爲FooSecond 1 FooSecond 1

任何想法可能會導致此? 謝謝

回答

2

您有UB; C++ 14 [basic.def.odr]/4:

每個程序都應該包含每個非內聯函數或該程序中odr使用的變量的一個定義;不需要診斷。

和/ 6:

可以有多於一個類型中的一種定義(第9節)...在程序中提供的每個定義出現在一個不同的翻譯單元,以及所提供的定義滿足以下要求。鑑於這樣的實體命名D在多於一個翻譯單元,然後

  • D每個定義應包括令牌的相同序列的定義;和

  • ...

...如果D的定義滿足所有這些要求,則該行爲是如果有的D一個統一的定義。如果D的定義不符合這些要求,則行爲是未定義的。

0

模板代碼僅由其名稱標識,即使結構不同,在這種情況下也是如此。 在我看來,最好的做法是將其中一個結構移到不同的命名空間。