2015-10-15 29 views
2

在下面的代碼中,foo應該是任何人都可以訪問的函數,但不應該是foo_helper,這就是爲什麼我將它放在匿名命名空間中的原因。很明顯,我在這個例子中包括守衛並且包括他們,但他們在那裏。如何在匿名命名空間中調用可變參數模板助手?

foo.h

namespace 
{ 
    void foo_helper() {} 

    template <typename T, typename... Tail> 
    void foo_helper(T head, Tail... tail) 
    { 
     bar(head); 
     foo_helper(tail...); 
    } 
} 

void foo(); 

template <typename... Args> 
void foo(Args... args) 
{ 
    before(); 
    foo_helper(args...); 
    after(); 
} 

foo.cpp

void foo() {} 

的問題是,爲了foo_helper的可變參數模板的工作,它需要有一個不帶參數的初始版本。但是,這迫使我定義一個非模板函數是一個頭文件,在將這個文件包含在多個源文件中後,這個頭文件會被破壞。我無法將foo_helper的定義移動到源文件中,因爲它位於匿名名稱空間中,因爲它不應該是可訪問的。

有沒有辦法解決這個問題?

+0

順便說一句,你需要用'foo_helper(args)'和'foo_helper(tail)'用'foo_helper(tail ...)'替換'foo_helper(args)'。 – KyleKnoepfel

+0

@KyleKnoepfel修好了,謝謝。 – Leonhart231

回答

3
inline void foo_helper() {}; 

解決了您的問題。

inline大多意味着「此功能的衝突定義將被丟棄,並保留其中一個版本」。

它也沒有約束地暗示「內聯」模糊的方式(因爲標準並不真正涵蓋內聯)。編譯者可能會或可能不會注意這個建議。

請注意,匿名命名空間不會「使其無法使用」或其他。匿名命名空間旨在阻止鏈接器衝突,這就是它。創建一個名爲details的名稱空間,...以及,相信用戶不要去內部戳。

在標題中使用匿名命名空間是一個非常糟糕的主意

如果在另一個訪問匿名命名空間中的符號或函數的頭文件中有一個inline函數(或模板函數),那麼幾乎可以肯定會有一個ODR(一個定義規則)衝突。這就是同一個對象,函數等有兩個不同的定義,並且不允許。

例如:

inline void bob() { 
    foo(1,2,3); 
} 

,如果這是#include d在兩個不同的cpp文件,只需由形成不良的程序(沒有診斷所需的)。

通常這樣的不良形式的節目「表現的方式你期望」,但有時他們不。舉例來說,如果沿線的某處出現局部變量,其存在依賴於ODR違例,則可以讓多個編譯單元不同意哪一個存在以及它的屬性是什麼。

從更一般的意義上說,程序的鏈接順序可能會改變它的行爲,因爲「選擇」了不同的定義(可能存在非常細微的差異)。或者月球的相位也可以這樣做。

ODR違規行爲令人驚訝地是良性的,直到他們用非本地錯誤難以追查到字節。

+0

這確實爲我解決了這個具體案例。但是有沒有一種方法可以使這項工作得到普遍應用,當「內聯」出於某種原因而不受歡迎時? – Leonhart231

+0

@ Leonhart231'inline'並不意味着你認爲它的意思? – Yakk

+0

你再正確無誤。我習慣於嵌入式平臺,其中「內聯」的字面意思是內聯。謝謝您的幫助!並感謝@coppro提醒我。 – Leonhart231

1

我會先從旁邊說一句:在這裏使用匿名命名空間不符合您的目的。由於您在頭文件中定義了它,因此它根本沒有被保護:它將仍然在包含頭的任何文件的範圍內。此外,由於您已將其定義在匿名名稱空間中,因此將在每個使用該函數的翻譯單元中發出函數的單獨副本,並且鏈接程序不能摺疊它們。如果你真的希望它是私有的,那麼我現在並不是最好的C++風格,所以也許別人會糾正我,但我會傾向於使用私有名稱空間:

正如Yakk指出的那樣,您可以使用內聯函數,並且這將允許編譯器將定義合併爲一個。在現代實踐中,應該沒有其他理由來避免關鍵字inline,因爲編譯器現在會自行決定是否內嵌函數而不是聽你提供的提示。

因爲您已經在匿名命名空間中定義了函數,所以如上所述,如果您保留該函數,則實際上不需要執行其他任何操作以避免鏈接器錯誤。這種方法的不足之處在於,您將在每個翻譯單元中分別有foo_helper()的副本,並且這些副本不能由鏈接器合併。

還有其他體操你可以做,主要涉及sizeof...,但我不認爲這些是理想的。

+0

這是關於匿名命名空間的好處。我只用它們是源文件,所以我沒有想到通過所有的方式。很多好點的,謝謝。 – Leonhart231