匿名命名空间和一个定义规则

时间:2011-10-31 14:26:52

标签: c++ namespaces one-definition-rule

我是否违反了One Definition Rule并使用以下程序?

// foo.hpp
#ifndef FOO_HPP_
#define FOO_HPP_

namespace {
   inline int foo() {
       return 1;
   }
}

inline int bar() {
    return foo();
}
#endif
//EOF

// m1.cpp

#include "foo.hpp"

int m1() {
    return bar();
}

//EOF

// m2.cpp

#include "foo.hpp"

int m2() {
    return bar();
}

//EOF

最后

// main.cpp
#include <iostream>

int m1();
int m2();

int main(int, const char* [])
{
    int i = m1();
    int j = m2();

    std::cout << (i+j) << std::endl;
    return 0;
}

// EOF

在上文中,请注意foo()是在匿名命名空间中定义的,因此我希望每个翻译单元m1.cppm2.cpp都会获得自己的版本,因此不存在违规行为ODR。另一方面,bar()只是一个简单的旧内联函数,碰巧会调用2个不同的foo。所以它违反了ODR,对吧?

更新的   以前我在foo的定义中使用宏来更改它返回的值,m1m2中的每一个都在包含foo.hpp之前对宏进行了不同的定义。 (并且使用前面的示例,g++将生成一个二进制文件,输出(i+j)的值不是您期望的值。)但实际上这个程序违反了ODR,即使是foo()完全相同。

2 个答案:

答案 0 :(得分:8)

这确实违反了ODR。请参阅3.2 / 5,其中讨论了外部内联函数(bar):

  在每个D的定义中,相应的名字,按照查找   3.4,应指D中定义的实体,或指同一实体......

在这种情况下,bar引用了两个不同版本的foo,因此违反了规则。

答案 1 :(得分:6)

是的,bar()的这个定义确实违反了一个定义规则。您正在创建多个定义,每个定义都调用一个名为foo()的不同函数。

正如你所说,即使foo()的所有版本都相同,这也是违规行为,因为它们仍然是不同的功能。