wie template als parameter deklarieren?
-
Hallo,
ich habe folgendes Konstrukt:
template<typename T0, typename T1, const T0 arg0, const T1 arg1> class foo { ... };
Jetzt würde ich gerne foo als Parameter von einer Funktion oder eben auch als Parameter eines weiteren templates verwenden.
Egal was ich auch probiere - ich komme mit den Fehlermeldungen des compilers nicht weiter.
-
ich will die haustüre zu machen. geht aber nicht. warum ?
mal ernsthaft. woher soll das jemand wissen ?
du postest weder fehlermeldungen noch zeigst du wesendlichen code.
-
Huch?
also ich möchte sowas machen:
template<foo arg1, foo arg2> class WhatEver { ... }
und/oder sowas:
void tuWas(foo arg1, foo arg2) { ... }
erschwerend kommt hinzu, dass foo in einem geschachtelten namespace liegt:
namespace x { namespace y { template<typename T0, typename T1, const T0 arg0, const T1 arg1> class foo { ... }; } }
schreibe ich beispielsweise das template von whatEver so:
template<template x::y::foo<typename T0, typename T1, const T0, const T1> arg1 , template x::y::foo<typename T0, typename T1, const T0, const T1> arg2> class WhatEver { ... };
erhalte ich die Fehlermeldung:
error: expected '<' before 'x'
Schreibe ich die Klasse so:
template<x::y::template foo<typename T0, typename T1, const T0, const T1> arg1 , x::y::template foo<typename T0, typename T1, const T0, const T1> arg2> class WhatEver { ... };
lautet die Fehlermeldung:
error: wrong number of template arguments
Ich habe natürlich noch mehr Varianten ausprobiert, aber die hier alle aufzählen, wäre extrem langwierig - auch zum lesen.
Reicht das nicht auch so, um zu erkennen, wo ich hin will und was ich falsch mache?
-
0plan schrieb:
Huch?
also ich möchte sowas machen:
template<foo arg1, foo arg2> class WhatEver { ... }
Und was soll das bedeuten?
-
Du suchst "template template params".
-
0plan schrieb:
Jetzt würde ich gerne foo als Parameter von einer Funktion oder eben auch als Parameter eines weiteren templates verwenden.
Willst du etwas basteln was man mit Instanzierungen von foo verwenden kann, bzw. mit Objekten von diesen Instanzierungen? Also quasi so
void fun() { typedef foo<short, int, 1, 2> einFoo; typedef foo<char, bool, 3, false> nochEinFoo; tuWas(einFoo(), nochEinFoo()); WhatEver<einFoo, nochEinFoo> we; we.blub(); }
Oder willst du das un-spezialisierte Template "foo" als Parameter übergeben? So dass das was
tuWas
bzw.WhatEver
bekommen weiterhin ein Template ist und dann vontuWas
bzw.WhatEver
mit verschiedenen Template-Arguments verwendet werden kann? Also...template <typename T0, typename T1, const T0 arg0, const T1 arg1> class foo { ... }; template <typename T0, typename T1, const T0 arg0, const T1 arg1> class foo2 { ... }; template <typename T0, typename T1, const T0 arg0, const T1 arg1> class bar { ... }; ... template <??? A ???, ??? B ???> void TuWas(???) { A<int, short, 2, 3> a; B<short, int, 4, 5> b; ... } void fun() { tuWas<foo, foo2>(); WhatEver<foo, bar> we; we.blub(); }
Falls ersteres, dann würde ich einfach zu
template <class A, class B> void tuWas(A a, B b) { ... template <class A, class B> class WhatEver { ...
raten.
Falls du intuWas
bzw.WhatEver
dann Zugriff auf die Template-Argumente benötigst, kannst du in foo einfach typedefs und static const dafür machen. Dann kannst du intuWas
bzw.WhatEver
einfachA::T0
,A::arg0
etc. schreiben schreiben.Und falls zweiteres dann gilt das was rewrew geschrieben hat: du suchst template template Paramter.
-
@rewrew
Danke für den Suchbegriff. Über die entsprechende Seite von cppreference bin ich schon früher gestolpert, habe dort aber nicht gefunden, was mir fehlt. Vielleicht habe ich die Seite ja auch nicht verstanden?@hustbaer
Genau das, was Du im ersten Code-Schnipsel mit der Funktion fun() gemacht hast, möchte ich gerne machen.
... by the way: ist die Zeile 6 überhaupt zulässig?
Meines Wissens darf ein default-Konstruktor nicht aufgerufen werden. Ich würde an der Stelle also compiler-Fehler erwarten.Aber ansonsten - genau das hatte ich vor.
Wenn ich die Umsetzung mit neuen Typen, so wie im letzten Code-Schnipsel versuche, kann ich nicht auf die Member der Parameter-Instanzen zugreifen, da die Typen keinen Bezug zum ursprünglichen template haben.
Im ursprünglichen template hatte ich die Werte von arg0 und arg1 in ein enum gepackt.
Sobald ich in der Funktion tuWas aber auf das enum zugreife, heißt es, dass das enum nicht existiert.Soweit ich die cppreference verstanden habe, verwendet man bei der (Vorwärts-)Deklaration eines template-Parameters nur "typename" ohne den Namen in der Parameterliste. Für die Platzhalter arg0 und arg1 habe ich kein Substitut gefunden. "auto" wird an der Stelle nicht akzeptiert ...
Deshalb stehe ich immer noch wie der Ochs vor dem Berg:
Wie kann ich den Parameter eines templates oder einer Funktion richtig deklarieren, sodass ich bei Verwendung des Parameters auch auf dessen Member zugreifen kann?
-
Da musst du gar nix spezielles machen, das geht "einfach so".
Zeig uns den Code, dann können wir dir vermutlich sagen was du falsch machst.ps
0plan schrieb:
Meines Wissens darf ein default-Konstruktor nicht aufgerufen werden. Ich würde an der Stelle also compiler-Fehler erwarten.
Dann weisst du falsch. Der Default-Ctor darf natürlich auch "direkt aufgerufen" werden.
-
Da musst du gar nix spezielles machen, das geht "einfach so".
Zeig uns den Code, dann können wir dir vermutlich sagen was du falsch machst.Naja - also ganz so trivial ist das Problem (meiner Ansicht nach) dann doch nicht zu lösen.
Hier mal die erste Stufe:#include <iostream> namespace x { namespace y { template<typename T0 , typename T1 , const T0 arg0 , const T1 arg1> class Foo { public: enum TemplateArgs { FirstParam = arg0 , SecondParam = arg1 }; static void doSomething() { std::cout << "first something: " << FirstParam << std::endl; std::cout << "second something: " << SecondParam << std::endl; } }; } } int main() { x::y::Foo<short, int, 1, 2> sample; std::cout << "first param is: " << sample.FirstParam << std::endl; std::cout << "second param is: " << sample.SecondParam << std::endl; sample.doSomething(); }
übersetzt ohne Fehler und ergibt die erwartete Ausgabe:
first param is: 1 second param is: 2 first something: 1 second something: 2
Dann die Erweiterung (falscher Trivial-Ansatz):
#include <iostream> namespace x { namespace y { template<typename T0 , typename T1 , const T0 arg0 , const T1 arg1> class Foo { public: enum TemplateArgs { FirstParam = arg0 , SecondParam = arg1 }; static void doSomething() { std::cout << "first something: " << FirstParam << std::endl; std::cout << "second something: " << SecondParam << std::endl; } }; } } namespace z { enum Serial { First , Second }; template<x::y::Foo x , x::y::Foo y , Serial n> class WhatEver { public: WhatEver() { x.doSomething(); y.doSomething(); } }; } int main() { x::y::Foo<short, int, 1, 2> sample; z::WhatEver<x::y::Foo<short, int, 3, 4> , x::y::Foo<int, bool, 5, true> , z::Serial::Second> crap; std::cout << "first param is: " << sample.FirstParam << std::endl; std::cout << "second param is: " << sample.SecondParam << std::endl; sample.doSomething(); }
ergibt die folgenden Fehlermeldungen:
dummy.cpp:35:16: error: ‘x::y::Foo’ is not a type template<x::y::Foo x ^ dummy.cpp:36:16: error: ‘x::y::Foo’ is not a type , x::y::Foo y ^ dummy.cpp: In constructor ‘z::WhatEver<x, y, n>::WhatEver()’: dummy.cpp:42:7: error: request for member ‘doSomething’ in ‘x’, which is of non-class type ‘int’ x.doSomething(); ^ dummy.cpp:43:7: error: request for member ‘doSomething’ in ‘y’, which is of non-class type ‘int’ y.doSomething(); ^ dummy.cpp: In function ‘int main()’: dummy.cpp:55:32: error: type/value mismatch at argument 1 in template parameter list for ‘template<int x, int y, z::Serial n> class z::WhatEver’ , z::Serial::Second> crap; ^ dummy.cpp:55:32: error: expected a constant of type ‘int’, got ‘x::y::Foo<short int, int, 3, 4>’ dummy.cpp:55:32: error: type/value mismatch at argument 2 in template parameter list for ‘template<int x, int y, z::Serial n> class z::WhatEver’ dummy.cpp:55:32: error: expected a constant of type ‘int’, got ‘x::y::Foo<int, bool, 5, true>’ dummy.cpp:55:32: error: template argument 3 is invalid dummy.cpp:55:53: error: invalid type in declaration before ‘;’ token , z::Serial::Second> crap;
Soweit ich es verstanden habe, müsste Foo im template-Vorspann von WhatEver als template deklariert werden. Die Deklaration darf aber nicht vollständig sein, wie bei einer Klassen-Definition, sondern muss wie eine Vorwärtsdeklaration aussehen.
Also z.B. so:
template<x::y::template<typenmae, typename, auto, auto> Foo , x::y::template<typenmae, typename, auto, auto> Foo , Serial n> class WhatEver { ... };
... nur ist "auto" an der Stelle nicht erlaubt.
Und damit wären wir wieder bei meiner Anfangsfrage: wie deklariere ich ein template richtig als Parameter?
-
Weil du das ignorierst was ich dir geschrieben habe.
... namespace z { enum Serial { First, Second, }; template <typename X, typename Y, Serial n> class WhatEver { public: WhatEver() { X::doSomething(); // walk Y::doSomething(); // quack } }; } ...
Und BTW: wieso verwendest du nen
enum
fürFirstParam
undSecondParam
stattstatic const
? Muss der Code mit VC6 kompatibel sein
-
Weil du das ignorierst was ich dir geschrieben habe.
Oups - war keine böse Absicht.
so wie es aussieht, hatte ich Dich nicht verstandenUnd BTW: wieso verwendest du nen enum für FirstParam und SecondParam statt static const? Muss der Code mit VC6 kompatibel sein
Nee, mit VC habe ich glücklicherweise nix am Hut
Ich hatte Mr. Meyer so verstanden, dass das Vorteile bringen würde.... aber ich muss zugeben: bei vielem habe ich mir nur gemerkt, wie es zu schreiben ist und oftmals habe ich die Begründung schon wieder vergessen.
Hab herzlichen Dank für Deine Hilfe und Geduld!