2013-04-04 81 views
11

以下代碼給我一個編譯錯誤'value'未在此範圍中聲明。基類模板的成員超出派生類模板中具有相同模板參數的作用域

template<class T> 
struct Base { 
    int value; 
}; 

template <class T> 
struct Derived : public Base<T> { 
    int getValue() { return value; } 
}; 

我覺得非常奇怪,

  • 如果從Base<std::string>Derived繼承,代碼編譯,
  • 如果我return Base<T>::value,代碼編譯。

爲什麼不代碼編譯器嗎?以何種方式是「價值」並不在Derived<T>::getValue()的範圍內聲明?

回答

16

因爲value不合格的名稱,並且在名稱查找的第一階段,編譯器將不知道這是一個數據成員從基類繼承(它尚未實例化Base<T>尚未)。因此,它會搜索全局命名空間,並沒有發現所謂的可變value;因此,它會發出錯誤。

這裏是解決這個問題的一個典型方法:

template <class T> 
struct Derived : public Base<T> { 
    int getValue() { return this->value; } 
    //      ^^^^^^ 
}; 

顯式地解引用this告訴編譯器後面的名稱是(可能繼承)的名稱數據成員,並且查找應被延遲到成員函數實際上是實例化的地步。當然,你做的解決方案:

return Base<T>::value; 

同樣出色,因爲它也告訴value從基類繼承Base<T>編譯器。

對於所關注的Base<std::string>推導,編譯器可以立即去找了Base<std::string>是否包含一個名爲value(因爲它不依賴於任何模板參數)的數據成員,如果是這樣的話,它就能確定表達式是格式良好的。

但是,如果你的基類是Base<T>,其中T是在名稱查找的第一階段未知,編譯器分不清什麼是value(的Base針對不同T小號特甚至可能沒有value在所有) 。

段落14.6/C++的11標準的3:

在一類或類模板的定義中,如果一個基類依賴於模板參數,基類 範圍並不在類模板 或成員的定義點處或在類模板或成員的實例化期間在非限定名稱查找期間進行檢查。 [...] [實施例

struct A { 
    struct B {/.../}; 
    int a; 
    int Y; 
}; 

int a; 

    template<class T> struct Y : T { 
    struct B {/.../}; 
    B b; // The B defined in Y 
    void f(int i) { a = i; } // ::a 
    Y* p; // Y<T> 
    }; 

Y<A> ya; 

成員A::BA::a,和模板參數AA::Y不影響 Y<A>名稱的結合。 - 結束示例]

+0

優秀的答案。 – Oswald 2013-04-04 14:39:15

+0

@Oswald:謝謝,很高興我能幫到 – 2013-04-04 14:40:54

+0

非常好,我可以隨時添加:)。 – 2013-04-04 15:04:05

相關問題