2015-11-17 77 views
12

考慮以下幾點:模板別名能見度嵌套類

template<typename X> 
struct Z {}; 

struct A 
{ 
    using Z = ::Z<int>; 

    struct B : Z 
    { 
     using C = Z; 
    }; 
}; 

編譯沒有問題。尼斯。但是,現在在Z添加另一個參數:

template<typename X, typename Y> 
struct Z {}; 

struct A 
{ 
    template<typename X> 
    using Z = ::Z<X, int>; 

    struct B : Z<B> 
    { 
     using C = Z<B>; // error: too few template arguments for class template 'Z' 
    }; 
}; 

好吧,也許這是有道理的,派生的嵌套類BA類模板別名Z的定義是可見的,而不是它的體內,引發由於錯誤全局定義Z有兩個參數。

但是爲什麼在第一種情況下的行爲不同,當Z只是A中的一種類型別名?

最後,請A模板:

template<typename X, typename Y> 
struct Z {}; 

template<typename T> 
struct A 
{ 
    template<typename X> 
    using Z = ::Z<X, int>; 

    struct B : Z<B> 
    { 
     using C = Z<B>; 
    }; 
}; 

現在錯誤消失。 爲什麼?

(測試鏘3.6和GCC 4.9.2)

回答

9

簡而言之:從Z專業化推導介紹注入類名的::Z,其別名模板之前找到。如果A是一個模板,但是,注入的類名不再被發現,因爲基類的B依賴。


考慮[temp.local]/1:

像正常(非模板)類,類模板有一個 注入類名(第9節)。 注射類名可以使用 作爲模板名稱類型名稱

又【basic.lookup]/3:

注射類名的類的(第9節)也是認爲是類的目的的一個成員名稱查詢

Z被查找爲不合格的名稱; [basic.lookup.unqual]/7:

enter image description here

因此,注入類名Z被發現作爲基類Z<B, int>的成員,並用作模板 ,這會導致你的第二個程序不合格。事實上,你的第一個片段使用注入的類名以及 - 下面的代碼段將不能編譯:

struct A 
{ 
    using Z = ::Z<float>; 
    struct B : ::Z<int> 
    { 
     static_assert(std::is_same<Z, ::Z<float>>{}, ""); 
    }; 
}; 

最後,如果A由模板,請注意,B是一個依賴型的每個[temp.dep.type] /(9.3),因此Z<B>是依據[temp.dep.type] /(9.7)的依賴類型,因此在查找期間未檢查基類Z<B>不合格IDZ根據[temp.dep]/3:

在一個類的定義[..],一個 依賴性基類(14.6.2.1)的範圍並不在任一類模板或 構件的定義點不合格 名查找期間檢查或者在類模板或成員的實例化期間。

因此注入類名稱將不會被找到。


B是 「嵌套類[..]這是一個依賴構件當前實例的」(重點煤礦),由於

名稱是依賴於當前實例化的成員,如果它是當前實例的 成員,當查找時,指 至少一個當前實例化的類的成員。

+0

哇。這很清楚,謝謝。當'A'停止作爲模板時,實際上出現了這個錯誤,我認爲這會簡化代碼。然而,我現在被迫爲兩個'Z'使用兩個不同的名字,這隻會使代碼更醜。如果有更好的解決方法,請告訴我。 – iavr

+0

@iavr如何使用C = Z;'? (不適用於'A'作爲模板) – Columbo

+0

現在令人印象深刻:-)是的,它適用於此簡化代碼,但不適用於我的原始代碼('未知類型名稱'Z'')。我將不得不檢查其中的差異。 'A'不再是一個模板,我打算保持這種模式。 – iavr