2016-02-05 91 views
1

我試圖寫template class defining a super type idiom的變化繼承定義的類型。類Inherit介紹類型Super來表示可能是很長的超類型,並且還需要知道派生類型New做這我不會在這裏呈現出一些額外的東西。C++找不到模板基類,從目前的模板類

這工作正常,如果傳遞給New類型是不是一個模板,但沒有使用模板。這裏是clang++-3.8 -std=c++1y -Wall編譯一個完整的例子(GCC給出了相同的輸出):

struct SomeBase {}; 

template<class New, class Base> 
struct Inherit : Base { 
    using Super = Inherit<New, Base>; 
}; 

struct NonTemplate : Inherit<NonTemplate, SomeBase> { 
    using X = Super; 
    // compiles and is nice and short 
}; 

template<class T> 
struct Template : Inherit<Template<T>, SomeBase> 
{ 
    using A = Super; 
    // error: unknown type name 'Super'; did you mean 'NonTemplate::Super'? 

    using B = typename Super; 
    // error: expected a qualified name after 'typename' 

    using C = Inherit::Super; 
    // error: 'Inherit' is not a class, namespace, or enumeration 

    using D = typename Inherit<Template<T>, SomeBase>::Super; 
    // compiles, but what's the point? 
}; 

int main() { 
    return 0; 
} 

如果我並不需要New參數我也能使用Inherit使用模板,但我真的需要New。我可以通過使用選項D來編譯代碼,但這會破壞整個目的。

我有兩個問題:

  1. 究竟是語言問題,防止被稱爲類Template內部和類型名稱Super 這是爲什麼不同的NonTemplate情況?
  2. 沒有人有很好的解決了這個問題的想法?
+0

根據名稱...'繼承,SomeBase>'可能有一些專業化可能會改變Super'的'的意思。 – Jarod42

回答

6

問題是Inherit<Template<T>, SomeBase>取決於基類,即類依賴於模板參數。從屬基類中的名稱對於不合格的查找是隱藏的,因此您需要限定該名稱。

typename是需要的,因爲Inherit<Template<T>, SomeBase>::Super是一個從屬名稱,編譯器需要你告訴它它命名了一個類型,因爲它只能在實例化時確定。

typename關鍵字進行了深入的說明,請參見Where and why do I have to put the 「template」 and 「typename」 keywords?


至於解決方案,您可能因素Super伸到一種特質:

template<class New, class Base> 
struct Inherit : Base { 
}; 

namespace detail { 
    template <class New, class Base> 
    Inherit<New,Base> Super (const Inherit<New, Base>&); 
} 
template <class T> 
using Super = decltype(detail::Super(std::declval<T>())); 

這使得使用更加簡單:

template<class T> 
struct Template : Inherit<Template<T>, SomeBase> 
{ 
    using D = Super<Template>; 
}; 

如果你發現自己需要這個對於多個基類,你可以概括它:

namespace detail { 
    template <template <typename...> class T, class... Args> 
    T<Args...> Super (const T<Args...>&); 
} 
template <template <typename...> class Base, class Derived> 
using Super = decltype(detail::Super<Base>(std::declval<Derived>())); 

template <typename T> 
using InheritSuper = Super<Inherit,T>; 

template<class T> 
struct Template : Inherit<Template<T>, SomeBase> 
{ 
    using D = InheritSuper<Template>; 
}; 
+0

感謝您的廣泛解決方案! :)我希望沒有必要使用這種複雜功能,因爲它使用起來更加複雜('Super' vs'Super '),但它還是比指定完整的基本類型要好。 –