2017-02-28 39 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

模板代码仅由其名称标识,即使结构不同,在这种情况下也是如此。 在我看来,最好的做法是将其中一个结构移到不同的命名空间。