2010-07-12 63 views
7

使用G ++ 4.2.1編譯此代碼:錯誤的私人基類無法訪問?

struct S { }; 
template<typename T> struct ST { }; 

template<typename BaseType> 
class ref_count : private BaseType { }; 

template<typename RefCountType> 
class rep_base : public RefCountType { }; 

class wrap_rep : public rep_base<ref_count<S> > { 
    typedef rep_base<ref_count<S> > base_type;  // line 11 
}; 

我得到:

bug.cpp:1: error: ‘struct S’ is inaccessible 
bug.cpp:11: error: within this context 

但是,如果我改變wrap_rep類使用ST

class wrap_rep : public rep_base<ref_count< ST<int> > > { 
    typedef rep_base<ref_count< ST<int> > > base_type; 
}; 

它編譯罰款。或者,如果我將原始代碼更改爲:

class wrap_rep : public rep_base<ref_count<S> > { 
    typedef rep_base<ref_count<::S> > base_type; // now using :: 
}; 

它也編譯得很好。對我來說,原來的代碼看起來很好。這是一個g ++的錯誤?如果不是,那麼爲什麼使用模板工作?而對於另一種情況,爲什麼需要::S

回答

7

這兩個代碼都是無效的(只有最後一個是有效的),但是你的編譯器(不符合)只能診斷一個。正如另一個答案所說,這使用注入的類名。類別S被認爲具有表示同一類的成員名稱S。例如(注意「類」關鍵字之前S::S在第一個例子是需要強制於所注入的類名的引用,而不是默認的構造函數):

class S { }; 

class S::S object; // creates an S object 
class X : S::S::S::S { }; // derives from class S 

類模板也有一個注入的類名。像注入的類名一樣,它被繼承到派生類,因此ST<int>是格式不正確的,因爲它使用了注入的類名,但這是不可訪問的。如果您使用GCC 4.5較少,它可能有一些做與GCC4.5一個change introduced

G ++現在實現DR 176此前G ++不支持使用模板基類的注射類名作爲類型名稱,並查找名稱找到封閉範圍中的模板聲明。現在查找名稱查找注入類名稱,可以將其用作類型或作爲模板,具體取決於名稱後面是否有模板參數列表。由於這種變化,先前接受,因爲,因爲它從一個私人的基礎是

  1. 注入的類名是無法訪問可能會形成不良的一些代碼,或
  2. 注入 - 類 - 的結果名稱不能用作模板模板參數的參數。

無論在哪種情況下,都可以通過添加一個嵌套名稱說明符來明確命名模板來修復代碼。第一個可以用-fno-access-control解決;第二隻是被拒絕的。


爲了有更多的樂趣與注入的類名 - 請注意,因爲人們可能首先想到的是注入的類名是不等同於一個typedef。注入的類名是一個類名,但不屬於一個typedef名,這意味着它可以通過函數,對象或枚舉器的名稱被隱藏:

// valid, the data-member hides the injected class name 
struct S { int S; }; 

要引用注入的類名,你可以如class S::S(同樣,在基類列表中,非類型名稱將被忽略,因此您不需要特別提前注意),但對S::S的簡單查找將引用數據成員。

0

原始代碼在「Sun WorkShop 6 update 2 Compilers C++」中編譯得很好。這是我在我的辦公室唯一可以訪問的人。可以嘗試使用其他任何編譯器。

3

您的結構Swrap_rep的基類,這意味着它被注入到wrap_rep中,就好像存在匿名typedef一樣。

使用操作::在你的typedef S之前會告訴你的編譯器不使用S你繼承,但在全局命名空間S

參見this link

+0

但是爲什麼代碼與模板基類一起工作? – 2010-07-12 04:49:42