2011-10-31 43 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()都是相同的,它們仍然是違規行爲,因爲它們仍然是不同的功能。