【问题标题】:anonymous namespaces and the one definition rule匿名命名空间和单一定义规则
【发布时间】:2011-12-18 19:06:44
【问题描述】:

我是否违反了以下程序的单一定义规则?

// 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 个不同的 foos。所以它违反了 ODR,对吧?

更新: 以前我在foo 的定义中有宏,它改变了它返回的值,m1m2 在包含foo.hpp 之前对宏的定义不同。 (对于前面的示例,g++ 将生成一个二进制文件,输出 (i+j) 的值与您期望的值不同。)但实际上,即使 foo() 的主体是相同。

【问题讨论】:

  • 我认为这清楚地说明了为什么在头文件中使用匿名命名空间或静态函数会带来麻烦:)

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


【解决方案1】:

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

在D的每一个定义中,对应的名字,根据 3.4,应指代在D定义中定义的实体,或应指同一实体...

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-10
      • 2014-04-22
      相关资源
      最近更新 更多