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 ++在选择其中一个内联实现时是否正确?是否不可能在不同的翻译单元中提供内联函数的不同实现?
答案 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;那些大多数编译器都没有检查过这个,这种情况直到今天还没有改善!