2014-04-02 52 views
1

看看下面的例子:有沒有辦法避免模板朋友聲明的外部可視性?

啊:

class A { 
protected: 
    template<class T> 
    friend void b(); 
}; 

BH:

template<class T> 
void b() {} 

main.cxx:

#include "a.h" 

int main() 
{ 
    b<double>(); 
} 

請注意,我忘了,包括「 bh「在主文件中。不幸的是,編譯器會在A類中選擇好友聲明,並且無需抱怨地編譯主函數。我留下了一個神祕的鏈接錯誤,因爲實例應該發生在main.cxx這是令人驚訝:

[[email protected] friend]$ g++ main.cxx 
/tmp/ccfpaeHw.o: In function `main': 
main.cxx:(.text+0x5): undefined reference to `void b<double>()' 
collect2: error: ld returned 1 exit status 

我的問題是:爲什麼編譯器還允許嗎?有沒有辦法呢?

+0

通過單獨編譯的原則,每個翻譯單元 (TU)是分開編譯的,只要TU所需的所有信息在編譯時可用即可。對於帶有b簽名的函數,它當然是(在預編譯器將a.h移入main.cpp之後)。未解析的引用被輸入到符號表中,由鏈接器解析(因此鏈接器錯誤)。我不知道如何(或爲什麼)來避免這種情況。 – gnometorule

+0

爲什麼要避免這種情況?因爲它很醜!提及作爲一個班級的朋友存在的功能不應該允許外部代碼使用它,恕我直言。我確信這種行爲有很好的技術原因,但是找到一種方法可以讓外部代碼無法使用這個聲明,這樣可以避免錯誤,特別是對於初學者。 –

+1

'爲什麼'更像是一個技術問題。如果你經歷了編譯器/鏈接器採取的步驟,這將很難實現(例如,你需要一些跨TU有效性檢查)。 C(++)傳統上使用「單獨編譯」,這是不可能的。是的,我同意,這可能導致在調試時難以跟蹤錯誤。 – gnometorule

回答

4

ISO/IEC 14882:2003,§11.4,第3款這樣說:

在朋友宣言第一聲明的函數有外部鏈接,(3.5)。否則,該功能將保留以前的連接(7.1.1)。

因此,朋友聲明兼作函數聲明。這允許main調用該函數,所以沒有編譯器錯誤。

發生鏈接器錯誤是因爲聲明沒有匹配的函數定義。

我沒有看到避免這種行爲的方法(因爲標準規定了它)。它也是有意義的,因爲需要函數聲明來使朋友聲明無論如何都有效(否則你會有一個未聲明函數的朋友聲明)。所以,如果朋友聲明不會作爲函數聲明加倍,那麼函數聲明將不得不另外提供(通過包含適當的頭文件)。

+0

感謝您引用標準,它總是有幫助的。但是,你沒有提到我的問題的第二部分。我想你的答案是否定的? –

+0

@static_rtti:是的 - 應該明確添加 - 現在將解決此問題。 –

相關問題