2016-06-05 13 views
3

Ich habe eine Vorlage, die die Vorlage in Argumentlisten alle Typen in einem Parameterpaket gegeben gilt und erbt alle von ihnen (genannt ApplyOnPack):Typenkonflikt in variadische Vorlage Vererbung

template<template<int, typename> class Template, typename Seq, typename... Args> 
struct _Map {}; 

template<template<int, typename> class Template, 
     int firstIndex, int... indexes, 
     typename First, typename... Args> 
struct _Map<Template, Seq<firstIndex, indexes...>, First, Args...> 
    : Template<firstIndex, First>, 
     _Map<Template, Seq<indexes...>, Args...> 
{}; 

template<template<int, typename> class Template, typename... Args> 
struct ApplyOnPack : _Map<Template, Sequence<sizeof...(Args)>, Args... > 
{ 
    template <int I> 
    struct Base { 
     typedef Template<I, GetNthParameter<I, Args...> > Type; 
    }; 

    template <int I> 
    typename Base<I>::Type& base() { return *this; } 
}; 

Das Problem ist, , dass diese letzte base() -Methode nicht mit gcc (4.9.2) kompiliert wird, die eine ungültige Referenzinitialisierung beansprucht. Der Rückgabetyp sollte eine der Basisklassen vom Typ * sein, also was könnte das Problem sein? Oder wie kann ich den Code so ändern, dass er kompilierbar ist? Der Code kompiliert und arbeitet unter msvc (2013).

Ich habe es mit dem folgenden Beispiel getestet:

template <int i, typename T> 
struct Part { 
    void foo() {} 
}; 

template <typename ... T> 
struct Foo : ApplyOnPack<Part, T...> 
{ 
    void bar() { this->template base<0>().foo(); } 
}; 

typedef Foo<int, bool> MyFoo; 

int main() { 
    MyFoo myFoo; 
    myFoo.bar(); 
} 

Welche gcc scheiterte auf mit:

a.cpp: In instantiation of ‘typename ApplyOnPack<Template, Args>::Base<I>::Type& ApplyOnPack<Template, Args>::base() [with int I = 0; Template = Part; Args = {int, bool}; typename ApplyOnPack<Template, Args>::Base<I>::Type = Part<0, int>]’: 

a.cpp:62:15: required from ‘void Foo<T>::bar() [with T = {int, bool}]’ 
a.cpp:69:12: required from here 
a.cpp:51:43: error: invalid initialization of reference of type ‘ApplyOnPack<Part, int, bool>::Base<0>::Type& {aka Part<0, int>&}’ from expression of type ‘ApplyOnPack<Part, int, bool>’ 
    typename Base<I>::Type& base() { return *this; } 

Folgende zusätzliche Vorlagen verwendet oben: Eine Vorlage (GetNthParameter) zum Extrahieren von n- der Parameter aus einem Parametersatz:

template <int I, class... T> 
struct _GetNthParameter; 

template <int I, class Head, class... Tail> 
struct _GetNthParameter<I, Head, Tail...> 
    : _GetNthParameter<I-1, Tail...>{}; 

template <class Head, class... Tail> 
struct _GetNthParameter<0, Head, Tail...> { 
    typedef Head Type; 
}; 

template<int index, typename... Types> 
using GetNthParameter = typename _GetNthParameter<index, Types...>::Type; 

und eine zum Erstellen einer ganzzahligen Sequenz (Sequenz):

template<unsigned...> 
struct Seq { typedef int value_type; }; 

template<unsigned max, unsigned... numbers> 
struct _ExpandSeq : _ExpandSeq<max-1, max-1, numbers...> {}; 

template<unsigned... numbers> 
struct _ExpandSeq<0, numbers...> { 
    typedef Seq<numbers...> type; 
}; 

template<unsigned max> 
using Sequence = typename _ExpandSeq<max>::type; 
+0

hmm..builds für mich auf clang – Arunmu

+3

'_ExpandSeq',' _Map' und '_GetNthParameter' sind alle Wörter, die durch den Standard reserviert werden. Benutze diese Namen nicht. – Barry

+0

@Barry Danke, sie sind in einem Namensraum im echten Code. – simon

Antwort

2

Sie haben einen Typenkonflikt. Seq nimmt eine Reihe von unsigned s:

template <unsigned...> 
struct Seq { typedef int value_type; }; 

Aber Sie sind spezialisiert auf eine Reihe von int s unter:

template<template<int, typename> class Template, 
     int firstIndex, int... indexes, // <== 
     typename First, typename... Args> 
struct _Map<Template, Seq<firstIndex, indexes...>, First, Args...> 

Diejenigen, müssen bis säumen. Clang akzeptiert den Code, aber das ist ein Clang-Bug (#28010).


Wie ich in den Kommentaren erwähnt habe, verwenden Sie viele Kennungen, die durch den Standard reserviert sind. Jedes Wort, das mit einem Unterstrich beginnt und von einem Großbuchstaben gefolgt wird, ist reserviert: Benutze sie nicht!

Verwandte Themen