2013-02-08 20 views
9

編輯:我正在使用tdm-gcc-4.7.1-2 for Windows如何從模板化的基礎中消除多個繼承的typedefs?

不知道如何解決這個問題。我想用它作爲一種類型列表,讓我知道我正在嘗試使用B的類型定義中不存在的類型。

template <typename T, typename U> 
struct A { 
    typedef pair<T, U> type; 
}; 

struct B : A<int, string>, A<int, float> {}; 

B::type foo; // won't compile, ambiguous reference, as expected 
B::A<int, int>::type bar; // compiles fine?? :(

有沒有辦法得到它失敗的A<int, int>(以及任何其他A「不B繼承S),或另一種方式來進行此事?我想我可以使用一個tuple並緩解我的方式,對每個元素進行is_same比較,無論我是否提供元函數,但這似乎更容易...首先:\

+0

我懷疑'B ::一個 :: type'應該編譯在所有...'B :: A'已經是模糊的,不參照模板,但從中'B'導出實例... – 2013-02-08 22:49:34

+0

@DavidRodríguez-dribeas我同意的一個,我不明白爲什麼它編譯。我可能錯過了埋在標準中的規則。 – 2013-02-08 22:57:53

+0

我相信C++ 11草案中的章節是14.6.1-4。明確地允許這種情況 – jmetcalfe 2013-02-08 23:04:15

回答

6

這是因爲類模板有自己的模板的名字注入;注入的名稱可以用作模板或引用模板實例的類型(14.6.1p1)。注入的類名然後由派生類繼承(10.2p5);使用它作爲模板是明確的(它是相同的模板,但它是繼承的),因此是允許的。

要修復程序,請嘗試使用is_base_of

struct B : A<int, string>, A<int, float> { }; 
template<typename T, typename U> 
using check_A = typename std::enable_if<std::is_base_of<A<T, U>, B>::value, A<T, U>>::type; 

check_A<int, float>::type bar1; // compiles 
check_A<int, int>::type bar2; // error 
+0

在基地檢查好電話! :D謝謝。 – 2013-02-11 14:31:50

2

在§11.1/ 5中,標準說:

在派生類中,基類名的查找就會發現,而不是在它被宣佈範圍 基類的名稱 注入的類名。注入的類名稱可能比其聲明範圍內的基類名稱的可訪問性要低 。

所以A是在B範圍內注入的名稱。它指的是模板A,而不是根據§14.1/ 4的基類(因爲它不明確)。

就像在A的範圍內,如果你只是說A,它是類本身(但它是這個上下文中的模板)。您正在使用此注入名稱,因此名稱B::A::A相同。我不認爲有一種方法可以抑制這種行爲。

2

該標準明確允許這一點,雖然它有點混亂。從在草案14.6.1-4:

該發現可導致在某些情況下一個 歧義注入類名(10.2)(例如,如果在多於一個 發現的查找基類)。如果找到的所有注入類名稱都指向同一類模板的專業化,並且名稱 後跟模板參數列表,則引用指的是類模板本身,而不是專業化而不是 含糊不清。

[ Example: 
template <class T> struct Base { }; 
template <class T> struct Derived: Base<int>, Base<char> { 
typename Derived::Base b; // error: ambiguous 
typename Derived::Base<double> d;// OK 
}; 
— end example ]