不同翻译单元中内联函数的不同实现

时间:2014-10-07 16:41:22

标签: c++ inline language-lawyer

C ++标准对ODR说了这一点,因为它适用于内联函数(强调我的):

  

3.2一个定义规则

     

3每个程序应包含该程序中每个非内联函数或变量的一个定义;无需诊断。该定义可以在程序中明确显示,可以在标准或用户定义的库中找到,或者(在适当的时候)隐式定义(见12.1,12.4和12.8)。 内联函数应在每个使用它的翻译单元中定义

它没有说明内联函数是否可以在不同的翻译单元中具有不同的实现。我尝试了以下方法:

test-1.cc

#include <iostream> 
inline std::ostream& foo(std::ostream& os)
{
   return os << "Foo_1";
}

void test_1()
{
   foo(std::cout) << std::endl;
}

test-2.cc

#include <iostream> 
inline std::ostream& foo(std::ostream& os)
{
   return os << "Foo_2";
}

void test_2()
{
   foo(std::cout) << std::endl;
}

main.cc

extern void test_1();
extern void test_2();

int main()
{
   test_1();
   test_2();
   return 0;
}

我期待看到以下输出:

Foo_1
Foo_2

相反,我看到了:

Foo_1
Foo_1

我使用g++ 4.7.3测试了它。

g ++在选择其中一个内联实现时是否正确?是否不可能在不同的翻译单元中提供内联函数的不同实现?

3 个答案:

答案 0 :(得分:9)

ISO C ++2003§3.2第5段说

  

类类型(第9节),枚举类型(7.2),内联函数可以有多个定义   具有外部链接(7.1.2),类模板(第14节),非静态函数模板(14.5.5),静态数据   类模板的成员(14.5.1.3),类模板的成员函数(14.5.1.1)或模板特殊 -   在程序中未指定某些模板参数(14.7,14.5.4)的情况下提供的每个模板参数   定义出现在不同的翻译单元中,并且如果定义满足以下要求 -   发言:。鉴于在多个翻译单元中定义了这样一个名为D的实体,那么

     
      
  • D的每个定义应包含相同的令牌序列
  •   
  • (更多要求如下)
  •   
     

...

     

如果D的定义不满足这些要求,则行为未定义。

所以,不,非等同的定义是非法的。由于行为未定义,编译器几乎可以自由地做任何事情,包括选择他最喜欢的实现并忽略其他实现。

答案 1 :(得分:4)

您需要阅读该子条款。 §3.2[basic.def.odr] / p6记录了具有外部链接的内联函数的多个定义的要求。包含六个项目的整个需求列表占据整页,但基本上归结为“它们必须具有完全相同的令牌序列并且意味着完全相同的事物”。

在您的情况下,foo的多个定义甚至不满足第一个要求 - 定义由相同的令牌序列组成。未定义的行为结果。

答案 2 :(得分:-1)

标准中没有明确的声明说内联函数应该只有一个实现主体。 当然,在生产代码中,你必须确保只有一个机构..想象一下调试/维护惨败,如果你必须使用像你给出的代码那样的代码!

这显然不是你在生产中运行的代码;我听到你了,你对这种语言感到好奇。

因为标准不明确,这会导致灰色区域,编译器会做任何他们想做的事情。 实际上,Stroustrup自己于1994年在&Design;&Design; C ++的演变&#34;那些大多数编译器都没有检查过这个,这种情况直到今天还没有改善!