2016-04-29 12 views
3

Ich habe eine Situation, in der ich eine Spezialisierung als die gleiche wie die Instanziierung einer anderen Klasse definieren möchte. Hier ist ein einfaches Beispiel dafür, was ich will (eine vollständige intantiation in diesem Beispiel, in meinem eigentlichen Problem, ich mag eine partielle Spezialisierung):Definieren Sie eine Spezialisierung als Instantiierung einer anderen Klasse

//Template class 
template <int i> class Foo { /*...*/ }; 

//Another, completely different, template class 
template <int i,int j> class Bar { /*...*/ }; 

//Ordinary specialization of Foo 
template <> class Foo<0> { /*...*/ }; 

//Bogus specializations of Foo that 
// hopefully explain what I want. 
template <> class Foo<1> = Bar<1, 11>; 
template <> class Foo<2> = Bar<2, 42>; 
template <> class Foo<3> = Bar<3,-71>; 
... 

Was wäre der Vorteil, dies zu tun? Die Definitionen von Foo<1>, Foo<2> usw. sind ziemlich kompliziert, aber leicht einmal als Vorlage geschrieben. Es gibt viele solcher Definitionen. Die Definition von Bar in Foo zu arbeiten ist keine Option. Nur einige Werte können spezialisiert werden, und die Spezialisierung Bar muss von Hand gewählt werden (daher die Zufallszahlen für int j).

Ich würde normalerweise diesen Effekt erreichen, indem Sie CRTP verwenden. Ich würde einige ziemlich unangenehme Änderungen Bar machen, und dann etwas tun:

template <> class Foo<1> : public Bar<1, 11,Foo<1>> {}; 
template <> class Foo<2> : public Bar<2, 42,Foo<2>> {}; 
template <> class Foo<3> : public Bar<3,-71,Foo<3>> {}; 
... 

Offensichtlich Bar müssten geändert werden, mit vielleicht einigen using Erklärungen die Konstrukteure nach unten zu ziehen. Das wäre unordentlich.

Meine Frage: kann ich es besser machen? Das heißt, kann eine Spezialisierung als Instanziierung einer anderen Vorlagenklasse definiert werden?


Hinweis: bevorzugte Standard ist C++ 14, obwohl spätere Versionen akzeptabel wäre.

+0

Sollten die 'Foo'- oder' Bar'-Typen irgendwelche Kenntnisse voneinander haben? Das heißt, CRTP würde es ermöglichen, dass "Bar" über "Foo" "weiß" und "Foo" über "Bar" "weiß", weil es davon (in Ihrem Beispiel) erbt. Aber Sie wollen einen essentiellen 'typedef', so dass alle und alle Verweise auf' Foo <1> 'so wären, als ob man' Bar <1, 11> 'schreiben würde, richtig? – txtechhelp

+0

@txtechhelp Prettymuch. Ich dachte darüber nach, diese Frage an typedefs zu stellen, aber typedefs funktioniert nicht für Spezialisierungen. Ich schreibe gerade 'Bar', also kann' Bar' etwas über 'Foo' wissen. Die Basisdefinition von 'Foo' sollte jedoch nicht über 'Bar' bekannt sein - nur seine Spezialisierungen, die ich auch definiere. – imallett

+0

Überprüfen Sie die Antwort auf [diese] (http://stackoverflow.com/questions/20419869/is-it-possible-to-define-an-implementation-template-specialization-as-typedef-of) Frage .. könnte muss ein wenig mehr hinzufügen, aber es könnte dich näher bringen? – txtechhelp

Antwort

1

Würde die Umleitung hier helfen? :)

template<int i> struct Indirection { using type = Foo<i>; }; 

template <> class Indirection<1> { using type = Bar<1, 11>; }; 
template <> class Indirection<2> { using type = Bar<2, 42>; }; 
template <> class Indirection<3> { using type = Bar<3, -71>; }; 

template<int i> 
using ActualFoo = typename Indirection<i>::type; 
+0

Indirection löst alle Probleme, mit Ausnahme des Problems der zu großen Indirektion. – Yakk

+1

Beachten Sie, dass dies die Vorlagenargumentableitung auf "ActualFoo " unmöglich macht. –

0

Sie könnten Vererbung anstelle von CRTP verwenden.

template <int i> struct Foo {}; 

template <int i,int j> struct Bar { Bar() {} }; 

template <> struct Foo<0> {}; 

template <> struct Foo<1> : public Bar<1, 11> { using Bar::Bar; }; 
template <> struct Foo<2> : public Bar<2, 42> { using Bar::Bar; }; 
template <> struct Foo<3> : public Bar<3,-71> { using Bar::Bar; }; 
+0

Dies ist im Wesentlichen genau das, was ich oben geschrieben habe, aber ohne CRTP. Der Grund für CRTP ist, dass z.B. 'Bar <1,11>' hat Methoden, die wie 'Foo <1>' funktionieren sollten. Zum Beispiel kann 'Bar' den' statischen Balken getBarPlusBar (Bar, Bar); 'definieren. Mit CRTP wird dies 'statische FooType getBarPlusBar (FooType, FooType);', was bedeutet, dass ich jetzt gehen kann 'Foo <1> foo3 = Foo <1> :: getBarPlusBar (foo1, foo2);' – imallett

+0

@imallett, Sie haben zwei Möglichkeiten. Wählen Sie diejenige, die Ihren Bedürfnissen am besten entspricht. –