2011-10-31 88 views
13

我违反一个定义规则与以下程序?匿名命名空间和一个定义规则

// 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 s。所以它违反了ODR,对吧?

更新: 以前我曾在不同的包括foo.hpp一改之前定义的宏它返回的值,每个m1m2的的foo定义宏。 (在前面的例子中,g++会生成一个二进制数,输出(i+j),而不是您期望的值。)但实际上,该程序违反了ODR,即使foo()的主体是相同的。

+5

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

回答

7

这确实违反了ODR。见3.2/5,其在谈论外部内联函数(bar):

在d中的每个定义

,相应的名称,抬头根据 3.4,应指d的定义中定义的实体,或者应该指的是同一实体...

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

6

是的,这个bar()的定义确实违反了One Definition Rule。您正在创建多个定义,每个定义调用称为foo()的不同功能。

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