局部结构通过使用共同的模板函数影响不同的翻译单元

时间:2017-02-28 20:36:01

标签: c++ gcc visual-c++ c++14

我遇到的情况是,我不确定它是否可以被视为代码中的错误,编译器/链接器的错误/误用或对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 个答案:

答案 0 :(得分:2)

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

  

每个程序应该只包含该程序中使用的每个非内联函数或变量的一个定义;无需诊断。

和/ 6:

  

类型中可以有多个定义(第9条)...在程序中,每个定义出现在不同的翻译单元中,并且定义满足以下要求。鉴于在多个翻译单元中定义了名为D的实体,那么

     
      
  • D的每个定义都应包含相同的令牌序列;以及

  •   
  • ...

  •   
     

...如果D的定义满足所有这些要求,那么行为就好像只有D的单一定义。如果D的定义不满足这些要求,则行为未定义。

答案 1 :(得分:0)

模板代码仅由其名称标识,即使结构不同,在本例中也是相同的。 在我看来,这里的最佳实践是将其中一个结构移动到不同的名称空间。