Style - class template specializations && one class per file

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Style - class template specializations && one class per file

Beitrag von kaiserludi »

Stellt euch vor, ihr habt eine Template-Klasse mit 2 Templateparametern, partiellen Spezialisierungen für Pointer und vollen Spezialiserungen und das jeweils unabhängig voneeinander mal nur für einen der beiden Templateparameter, mal für den anderen oder auch mal für beide, also quasi soetwas:

Code: Alles auswählen

template<typename type1, typename type2>
class Foo
{
}

Code: Alles auswählen

template<typename type1, typename type2>
class Foo<type1*, type2*>
{
}

Code: Alles auswählen

template<typename type1>
class Foo<type1, Object>
{
}

Code: Alles auswählen

template<typename type1>
class Foo<type1*, Object*>
{
}

Code: Alles auswählen

template<typename type2>
class Foo<Object, type2>
{
}

Code: Alles auswählen

template<typename type2>
class Foo<Object*, type2*>
{
}

Code: Alles auswählen

template<>
class Foo<Object, Object>
{
}

Code: Alles auswählen

template<>
class Foo<Object*, Object*>
{
}

Nun stelt euch vor, die Klasse hat ein relativ großes Interface und dazu viele Überladungen und Templatefunktionen. In dem Beispielfall ist das alles natürlich quasi x 8.

Ich habe es bisher so gehalten, dass es pro Klasse oder Klassentemplate eine eigene Datei gibt, sprich jede non-Template Klasse in eine eigene Datei und jedes Klassen-Template in eine eigene Datei, aber alle Spezialisierungen eines Templates in die gleiche Datei.
Mit Template + partielle Pointerspezialiserung funzt das auch noch recht gut, aber mit solchen Fällen wie dem Beispiel da oben werden die Files entsprechend groß und unübersichlich und man hat bei einer 20 Zeilen Klassendefinition dank des x 8 schnell mal ein 160 Zeilen Monster da rum liegen, noch ohne Implementationoder Dokumentation wohlgemerkt.

Daher frage ich mich gerade, ob es nicht eventuell mehr Sinn macht, auf eine Datei pro Klasse oder Klassentemplatespezialiserung umzusteigen. Da Beispiel oben würde ich dann also auf 8 Dateien aufteilen.

Wie handhabt ihr das und warum?
Was sind eurer Meinung nach die Pros und Kontras?
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Style - class template specializations && one class per

Beitrag von CodingCat »

Naja, das ist schlussendlich dir überlassen, wie es im konkreten Fall am übersichtlichsten ist. Derartige Vervielfachung durch Spezialisierung versuche ich grundsätzlich zu vermeiden. Oftmals teilen sich die Spezialisierungen ohnehin viel gemeinsame Funktionalität, die ich auf keinen Fall vielfach rumfliegen haben möchte. In diesem Fall hilft fast immer Delegation an kleinere Hilfstemplates mit einfachen Spezialisierungen, die dann sowohl die Anzahl als auch das Ausmaß der Spezialisierungen stark eingrenzen können. Wie du zu einer großen Klasse kommst, die in ihrer Vollständigkeit in so vielen Varianten spezialisiert werden muss, kann ich mir ohne konkrete Informationen schlecht vorstellen.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Style - class template specializations && one class per

Beitrag von dot »

Jap, ich würde mir auch mal überlegen ob das wirklich alles Spezialisierungen eines template sein sollten oder nicht vielleicht einfach eigene konkrete Klassen...
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: Style - class template specializations && one class per

Beitrag von kaiserludi »

Naja, das geht schneller als man denkt:
Ein Container für Key-Value Paare, für den es einen Datentyp gibt, der eine Spezialisierung verlangt und der sowohl als Key, als auch als Value möglich ist:
1 generische Version
+ 1 partielle Spezialiserung für Pointer
+ 1 volle Spezialiserung für den gesondert zu behandelnden Datentyp
+ 1 volle Spezialiserung für Pointer auf den gesondert zu behandelnden Datentyp
+ 1 partielle Spezialiserung für Pointer auf const
+ 1 volle Spezialiserung für den gesondert zu behandelnden Datentyp
+ 1 volle Spezialiserung für Pointer auf const auf den gesondert zu behandelnden Datentyp

Schon sind wir bei 7 Versionen und das pro template-Parameter.
Wenn man nun aber alles kombinieren können will, also solch lustige Dinge wie eine Spezialisierung für Pointer auf cont als Key und Pointer auf const auf den gesondert zubehandelenden Datentype als Value, dann bedeutet das nun dummerweise aber, dass die Zahl der benötigten Spezialisierungen 6 hoch n + 1 geneirsche Version beträgt. Bei den angesprochenen Key-Value Containern ergibt das also sage und schreibe 36 Spezialisierungen + 1 generische Version.
Falls man für irgendendeinen Container 3 Template-Parameter brauchen solle, wären es da schon 216 Spezialiserungen des Templates + 1 generische Version, usw.

Ich habe das ganze jetzt folgendermaßen gelöst:
Das Klassentemplate gibts nur einmal als generische Version mit einem überschaubaren öffentlichen Interface und dafür für jede Funktioin, für die es nötig ist, ein private Memberfunktionstemplate mit allen nötigen Spezialisierungen. Das sorgt zwar für einen riesigen haufen private Funktionen, aber zum einen bleibt die public API übersichtlich, zum anderen sind tatsächlich nur von den Funktionen mehre Imlementationen nötig, welche tatsächlich utnerschiedliche Implementationen verlangen, und nicht von jeder Funktion, wie bei einem Klassentemplate.
Das Problem, dass partielle Spezialiserungen vonFunktionstemplates vom Standard nicht erlaubt sind ich dabei mit Hilfe des Functor-Idioms (http://accu.org/index.php/journals/385 - Abschnitt "Second Alternative") und das dabei entstehende Problem, dass volle Spezialiserungen von Membertemplates anderer Templates vom Standard nicht erlaubt sind, in dem ich sie mit Hilfe von zusätzlichen ungenutzten Dummy-Tempalte-Parametern zu partiellen Spezialisierungen mache. Glücklicherweise ist die dabei entstehende eines Obfuscated C++ Contests würdige Syntax (Beispiel gefällig? Deklaration: template<typename FKeyType, typename FValueType, typename FDummyType> struct typesToStringImplementation {JString& operator()(JString& retStr) const;}; Definition: template<typename EKeyType, typename EValueType> template<typename FKeyType, typename FValueType, typename FDummyType> JString& Dictionary<EKeyType, EValueType>::typesToStringImplementation<FKeyType, FValueType, FDummyType>::operator()(JString& retStr) const { return retStr = Helpers::TypeName::get<FKeyType>() + L", " + Helpers::TypeName::get<FValueType>();} Aufruf: typesToStringImplementation<EKeyType, EValueType, void>()(retStr);) ein komplett hinter der sauberen API verstecktes Implementationsdetail.

Was mich immer noch sehr stört, ist das Problem, dass immer, wenn ich eine Pointerspezialisierung brauche, ich jedes Mal 2 redundante partielle Spezialisierungen schreiben darf: einmal für ppointer auf non-const und einmal für pointer auf const, weil der Aufrufer sonst jedes Mal const-Casten muss, damit auch die Pointer-Spezialisierung und nicht die gerische Version aufgerufen wird.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Style - class template specializations && one class per

Beitrag von dot »

Was für ein Container ist das genau und wieso muss er spezialisiert werden?
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: Style - class template specializations && one class per

Beitrag von kaiserludi »

Es handelt sich um ein Dictionary, welches diverse Datentypen als Keys und als Values aufnehmen kann, wobei aber garantiert ist, dass alle Keys in der gleichen Dictionary Instanz den gleichen Typ haben, genau wie alle Values den gleichen Typ haben, der Keytype dar fsic haber natürlich von Valuetype unterscheiden, also quasi ein Dictionary<KeyType, ValueType>.
Die Implementation des Containers wrapt im Grunde nur einen anderen bereits vorhandenen Container, Hashtable, der im Grunde wie ein Dictionary<Object, Object> funktioniert, quasi wie die beiden entsprechenden Klassen in Java oder C# auch .
Nun können diese Container aber auch primitive Typen aufnehmen und ein primitiver spracheigener Typ wie int kann natürlich nicht von einer Klasse erben. Daher handelt es sich bei unserer Object-Klasse um eine Wrapper-Klasse, damit Container wie Arrays, Dictionaries, Hashtables, usw. problemlos einen Mix aus pimitiven Typen und Objekten aufnehmen können: Diese werden einfach alle in Object-Instanzen gewrappt und man hat dann z.B. einen Object[], einen Object**, einen Vector<Object> oder eben auch ein Dictionary<Object, Object>.
Für das Dictionary gibts nun Pointer mal aussen vor gelassen 4 Fälle: <KeyType, ValType>, <KeyType, Object>, <ValType, Object> und <Object, Object>, da die Calls des Dictionaries auf ihrer Member-Hashtableinstanz für Object anders aussehen müssen als für andere Datentypen: Andere Datentypen müssen erst noch in Object-instanzen gewrappt werden, bevor sie an die hashtable weitergeicht werden können, das Object hingegen ist bereits fertig und muss direkt durchgereicht werden, weil um das bereits vorhandene Wrapperobject sonst ein zweites drumherum gewrappt werden würde.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Style - class template specializations && one class per

Beitrag von dot »

kaiserludi hat geschrieben:Nun können diese Container aber auch primitive Typen aufnehmen und ein primitiver spracheigener Typ wie int kann natürlich nicht von einer Klasse erben.
Moment, stop, wieso muss plötzlich irgendwas von irgendwas erben?
Rein prinzipiell halt ich solche Ansätze wo alles von "Object" erbt, jetzt mal gelinde ausgedrückt, für suboptimal.
kaiserludi hat geschrieben:Daher handelt es sich bei unserer Object-Klasse um eine Wrapper-Klasse, damit Container wie Arrays, Dictionaries, Hashtables, usw. problemlos einen Mix aus pimitiven Typen und Objekten aufnehmen können: Diese werden eifnach alle in Object-Instanzen gewrappt und man hat dann z.B. einen Object[], einen Object**, einen Vector<Object> oder eben auch ein Dictionary<Object, Object>.
Wieso kannst du nicht einfach einen Object Wrapper bauen und deinen Container von vornherein einfach nur für <Object, Object> definieren:

Code: Alles auswählen

Container bla;
bla.insert(ObjectWrapper<int>(42), bli>);
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Style - class template specializations && one class per

Beitrag von CodingCat »

Ohne konkreten Code lässt sich das kaum sicher beurteilen, aber das klingt noch immer nach keiner wirklich guten Lösung.
  • Wieso brauchst du Spezialisierungen für Zeiger auf const-Objekte? Brauchst du garantiert einen nicht-konstanten Typ, dann nimm remove_const<T>. Vor C++11 musst du dir das ggf. selbst schreiben:

    Code: Alles auswählen

    template <class T> struct remove_const { typedef T type; };
    template <class T> struct remove_const<const T> { typedef T type; };
  • Wieso brauchst du Spezialisierungen für einzelne Datentypen? Sonderbehandlungen lassen sich in der Regel problemlos in Traits (implizit wie explizit) oder sogar einfach überladene Funktionen auslagern. Deine Beschreibung der Spezialisierung von Funktoren geht wohl in die Richtung impliziter Traits, dennoch machst du dir das eventuell einfach zu kompliziert. Wenn das einfache Aufrufen einer überladenen Funktion für die Sonderbehandlung nicht ausreicht, empfiehlt sich ein einfaches Template für den jeweiligen Aufgabenbereich:

    Code: Alles auswählen

    template <class T>
    struct MyContainerFactory
    {
       static T* create() { return new T(); }
       static void destroy(const T *p) { delete p; }
    };
    
    // Spezialisierungen ...
    
    template <class T>
    class MyContainer
    {
       typedef typename remove_const<T>::type MyElement;
       typedef MyContainerFactory<MyElement> MyFactory;
    
       void foo()
       {
          MyElement *e = MyFactory::create();
             // ...
       }
       // ...
    };
    Solche Trait-Templates kannst du problemlos partiell oder ganz spezialisieren, ohne dabei in unüberschaubaren Beschränkungen und massiver Redundanz bei der Spezialisierung von Funktionen, Methoden oder gar Template-Methoden unterzugehen. Für Zugriff auf Container-Interna genügt ein einfaches friend template <class T> struct MyContainerFactory; Von verschachtelten Templates und der Spezialisierung einzelner Members würde ich abraten, wie du selbst schon eindrücklich beschrieben hast, machen sie die Sache einfach nur lächerlich komplex.
Fazit: Die Typ-Qualifizierer const und volatile lassen sich fast immer durch einfache allgemeine Helfer-Templates wie remove_const, remove_volatile und remove_cv behandeln. Wie stark sich das Verhalten von Zeigern gegenüber "normalen" Datentypen unterscheidet, ist natürlich abhängig vom Anwendungsfall. Mit C++11 sollten sich auch Zeiger mit Verwaltungslogik immer wie Werte behandeln lassen; in älterem C++ ohne Move Semantics gestaltet sich das ggf. etwas schwieriger. Der Rest sollte sich mit einfachen Trait-Templates problemlos gezielt spezialisieren lassen.
Zuletzt geändert von CodingCat am 13.07.2012, 18:12, insgesamt 1-mal geändert.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: Style - class template specializations && one class per

Beitrag von kaiserludi »

@dot:
In Java/C# erbt alles von Object und die C++ Version sollte eine den Versionen in anderen Sprachen einigermaßen ähnliche Architektur haben, damit man in beide Richtugnen neue Features, Bugfixes, etc. relativ leicht portieren kann.
Ich möchte dem nutezr aber nicht wirklich zumuten, jeden Int bei der Kommunikation mit der API in einem Int-objeckt zu wrappen und das selbe für andere primitive Typen, womöglich noch for(INT i=0, i<10; ++i), statt (int i=0, i<10; ++i), damit auch die Zähler objektorientiert sind ;). Das ist mir einfach zu heavyweight, da will ich ganz klar lieber bei den primitiven Typen bleiben mit den entsprechenden Performancevorteilen. Ich stimme dir da also durchaus zu, dass lieber nicht alles von Object erben sollte. Wenn ich aber dennoch Object-Arrays ermöglichen will, ohne dass alles von Object erbebt, brauche ich entsprechend eine Wrapperklasse namens Object.
Wieso kannst du nicht einfach einen Object Wrapper bauen und deinen Container von vornherein einfach nur für <Object, Object> definieren
Genau das machen wir bereits, aber es ist eifnach ungeheuer nervig für den Nutzer der API, an jeder Stelle (immer Hashtable.put(KeyObject<int>(myInt)), ValueObject<short>(myShort), schreiben zu müssen, erst recht dann, wenn er nicht unseren komplette namespace per USing verfügbar machen will und da dann noch vor jeder Klasse 2 Namespaces davor stehen. Daher will ich auch ermöglichen, einfach Hashtable.put(myInt, myShort) zu schreiben und dann einfach intern in dem entsprechenden Funktionstemplate für put das ganze selbst ins Wrapper Object packien.

@CodingCat:
Ich brauche eigentlich gar keine spezielle const* Implementation, die sich irgendwie von der * Implementation unterscheidet, aber wenn der Compiler einen const* als üergebenen parameter sieht und nur die Versionen für Etype und für Etype*, aber keine für const Etype* findet, dann nimmt er dummerweise nicht die für Etype*, sondern die für Etype, nur deswegen brauche ich auch eine Version für const Etype*.
Das mit dem remove_const sieht auf den ersten Blick interessant aus und könnte mir tatsächlich das problem von Hals schaffen. Schaue ich mir nach dem Mittag mal genauer an.
C++ 11 kann ich leider nicht einsetzen. Das ganze muss auch mit MSVC++ kompilieren.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Style - class template specializations && one class per

Beitrag von CodingCat »

kaiserludi hat geschrieben:Für das Dictionary gibts nun Pointer mal aussen vor gelassen 4 Fälle: <KeyType, ValType>, <KeyType, Object>, <ValType, Object> und <Object, Object>, da die Calls des Dictionaries auf ihrer Member-Hashtableinstanz für Object anders aussehen müssen als für andere Datentypen: Andere Datentypen müssen erst noch in Object-instanzen gewrappt werden, bevor sie an die hashtable weitergeicht werden können, das Object hingegen ist bereits fertig und muss direkt durchgereicht werden, weil um das bereits vorhandene Wrapperobject sonst ein zweites drumherum gewrappt werden würde.
Das wiederum erscheint jetzt auf den ersten Blick nicht wirklich schwierig. Mit Überladungsauflösung findest du sehr leicht heraus, ob ein Typ schon von einem anderen abgeleitet ist, oder ob er erst noch verpackt werden muss. Mit einem entsprechenden Helfer-Template kannst du das sogar als Typeigenschaft zugänglich machen:

Code: Alles auswählen

template <class Type, class Base>
struct is_derived
{
private:
	typedef char yes[1];
	typedef char no[2];

	static yes& check(Base*);
	static no& check(void*);

public:
	/// Specifies whether Type is derived from Base.
	static const bool value = (
		sizeof( is_derived::check( static_cast<typename remove_cv<Type>::type*>(0) ) )
		==
		sizeof(yes) );
};

template <class Type>
struct IsObject : public is_derived<Type, Object> { };
Vermutlich kommst du hier aber ganz ohne Spezialisierung aus, indem du einfach direkt eine allgemeine Wrapper-Funktion überlädst:

Code: Alles auswählen

// Kein Wrapping
Object& wrap(Object *o) { return *o; }
const Object& wrap(const Object *o) { return *o; }
// Wrapping
template <class T>
ObjectWrapper<T> wrap(const T *v) { return ObjectWrapper<T>(*v); }

// Anmerkung: Arbeitet mit Zeigern, um deutlich zu machen,
// dass keine temporären Objekte übergeben werden sollten

void insert(const Element &e)
{
   const Object &o = wrap(&e);
   // ACHTUNG: o wird nach Verlassen der Methode ggf. zerstört
   // Code exemplarisch, kenne deine Verwaltung gewrappter Objekte nicht ;-)
}
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: Style - class template specializations && one class per

Beitrag von kaiserludi »

Gerade gesehen:
type_traits sind in VS2010 ja schon implementiert.

Code: Alles auswählen

template<typename T> class Foo;
template<typename T> class Foo<std::remove_const<T*>::type>;
führt aber leider zu:
error C2923: 'Foo' : 'std::tr1::remove_const<T*>::type' is not a valid template type argument for parameter 'T'
aber genau das brauche ich doch, wenn ich

Code: Alles auswählen

template<typename T> class Foo;
template<typename T> class Foo<T*>;
template<typename T> class Foo<const T*>;
verhindern will?
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Style - class template specializations && one class per

Beitrag von CodingCat »

Nein. Die Spezialisierung ist template<typename T> class Foo<T*>;. Innerhalb des Templates erhälst du mit std::remove_const<T>::type dann beispielsweise int sowohl für Foo<int*> (d.h. T = int) als auch für Foo<const int*> (d.h. T = const int).
Gerade gesehen: type_traits sind in VS2010 ja schon implementiert.
Ja. Move Semantics übrigens ebenfalls, mit denen du auf Zeigerspezialisierungen von Containern in fast allen Fällen verzichten kannst (z.B. brauchst du die Boost Pointer Container Library nicht mehr, weil unique_ptr dank Move Semantics in jeden Container gesteckt werden kann).
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: Style - class template specializations && one class per

Beitrag von kaiserludi »

Aber ich will ja verhindern, dass wenn ich nur template<typename T> class Foo und template<typename T> class Foo<T*> habe, const int* pBar; Foo(pBar); eine Instanz von Foo<T> erstellt, weil keine partielle Spezialisierung für Foo<const T*> existiert.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Style - class template specializations && one class per

Beitrag von CodingCat »

kaiserludi hat geschrieben:Aber ich will ja verhindern, dass wenn ich nur template<typename T> class Foo und template<typename T> class Foo<T*> habe, const int* pBar; Foo(pBar); eine Instanz von Foo<T> erstellt, weil keine partielle Spezialisierung für Foo<const T*> existiert.
Das wird nicht passieren. Wenn du einen Zeigertyp angibst, wird immer die Zeigerspezialisierung genommen, egal auf welchen Typ der Zeiger zeigt (und damit egal ob dieser Typ const und/oder volatile ist).
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: Style - class template specializations && one class per

Beitrag von kaiserludi »

Hmm, in dem Fall bin ich dann wohl auf einer falschen Fährte gewesen. Ich habe gerstern eine Fehlermeldung gehabt, die mir danach aussah, als würde für non-const Pointer Foo<T*> und für const-pointer Foo<T> aufgerufen werden, denn bei dem nicht konstanten Pointer hat alles gepasst und der gleichen Aufruf mit Übergabe eines const Poiners führte plötzlich dazu, dass der sich Compiler weigerte, T* implizit in T zu casten. Muss ich schinbar mal den Problemfall simplifizieren und schauen, warum er sich dann da beschwert.
Das zitierte hat sich also damit erledigt:
kaiserludi hat geschrieben: Was mich immer noch sehr stört, ist das Problem, dass immer, wenn ich eine Pointerspezialisierung brauche, ich jedes Mal 2 redundante partielle Spezialisierungen schreiben darf: einmal für ppointer auf non-const und einmal für pointer auf const, weil der Aufrufer sonst jedes Mal const-Casten muss, damit auch die Pointer-Spezialisierung und nicht die gerische Version aufgerufen wird.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: Style - class template specializations && one class per

Beitrag von kaiserludi »

CodingCat hat geschrieben:

Code: Alles auswählen

template <class T> struct remove_const<T> { typedef T type; };
template <class T> struct remove_const<const T> { typedef T type; };
Mir fällt gerade auf, das muss korrekt so aussehen:

Code: Alles auswählen

template <class T> struct remove_const { typedef T type; };
template <class T> struct remove_const<const T> { typedef T type; };
Bei mir ist jetzt eine neue Frage in Bezug auf remove_const aufgekommen:

Code: Alles auswählen

const_cast<remove_const<const float*>::type>(NULL);
führt zur Fehlermeldung "'const_cast' : cannot convert from 'int' to 'const float *'", aber ich hätte eigentlich erwartet, "'const_cast' : cannot convert from 'int' to 'float *'" zu bekommen. Die Fehlermeldung würde ja bedeuten, dass remove_const<const float*>::type == const float* ist und nicht == float*.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Style - class template specializations && one class per

Beitrag von CodingCat »

kaiserludi hat geschrieben:Mir fällt gerade auf, das muss korrekt so aussehen:

Code: Alles auswählen

template <class T> struct remove_const { typedef T type; };
template <class T> struct remove_const<const T> { typedef T type; };
Ja, natürlich. Ist nachgebessert.
kaiserludi hat geschrieben:Bei mir ist jetzt eine neue Frage in Bezug auf remove_const aufgekommen:

Code: Alles auswählen

const_cast<removeConst<const float*>::type>(NULL);
führt zur Fehlermeldung "'const_cast' : cannot convert from 'int' to 'const float *'", aber ich hätte eigentlich erwartet, "'const_cast' : cannot convert from 'int' to 'float *'" zu bekommen. Die Fehlermeldung würde ja bedeuten, dass removeConst<const float*>::type == const float* ist und nicht == float*.
remove_const bezieht sich natürlich auf den gesamten angegebenen Typ. Bei const float* ist der Typ "Zeiger auf const float". Der entsprechende const-qualifizierte Typ wäre "konstanter Zeiger auf const float" und somit const float *const. Damit ist remove_const<const float *const>::type == const float * == remove_const<const float *>::type.

Die C++11-STL stellt noch weitere Helfer-Templates zur Verfügung, z.B. remove_pointer und add_pointer. Dürfte in MSVC++10 ebenfalls bereits verfügbar sein, ist aber auch schnell selbst geschrieben.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: Style - class template specializations && one class per

Beitrag von kaiserludi »

Ah, OK, was ich in meinem Fall eigentlich wollte, war nicht const_cast<std::remove_const<Etype*>::type>(data), sondern const_cast<std::remove_const<Etype>::type*>(data). Jetzt funzt es wie gedacht. :)
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Style - class template specializations && one class per

Beitrag von CodingCat »

Jep, dachte ich mir. Und ggf. typename nicht vergessen, MSVC++ rächt sich erst bei der ersten Instantiierung. ;)
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: Style - class template specializations && one class per

Beitrag von kaiserludi »

CodingCat hat geschrieben:Jep, dachte ich mir. Und ggf. typename nicht vergessen, MSVC++ rächt sich erst bei der ersten Instantiierung. ;)
Ja, die typename Freuden sind mi wohl vertraut. Äußert nervig bei Templates in Libs, die dann nirgends in der Lib selsbt, sondern nur in Testapps instantiert werden: Die lib kompiliert auch bei Fehlern einwandfrei und man muss immer explizit die testapp bauen, um die Fehler zu sehen, die natürlich aber nicht das gkleiche Projekt wie die Lib ist, wodurch ein einfaches Build Selected mit Focus auf dem LibCode nicht geht und man ewig zum Bauen den Focus in Testapp Projekt legen muss :(

PS: Danke für Hilfe :)
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Style - class template specializations && one class per

Beitrag von CodingCat »

Das Problem dabei ist, dass auch in der Testanwendung ggf. nur das verwendete Subset instantiiert wird (im Optimalfall natürlich alles). Bei Template-Libraries empfiehlt sich die Möglichkeit einer expliziten vollständigen Instantiierung aller Templates mit einigen repräsentativen Typen direkt bei der jeweiligen Implementierung per #define:

Code: Alles auswählen

#ifdef LIB_STATIC_CHECK
// Einmal alles instantiieren
template class MyContainer<int, int>;
template class MyContainer<int, Object>;
template class MyContainer<Object, int>;
template class MyContainer<Object, Object>;
// ...
#endif
Dann in einer Implementierungsdatei der Bibliothek einmal alles einbinden:

Code: Alles auswählen

#define LIB_STATIC_CHECK
#include "MyContainer.h"
// ...
Eventuell könnte man die Build-Umgebung sogar dazu bringen, diesen statischen Test automatisch durchzuführen, z.B. indem neben Implementierungs- auch alle Header-Dateien kompiliert werden, die Headers in diesem Fall mit vordefiniertem LIB_STATIC_CHECK.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: Style - class template specializations && one class per

Beitrag von kaiserludi »

Code: Alles auswählen

template<typename Etype>
class Foo
{
public:
	Foo(Etype& param);
	Foo(const Foo<Etype>& toCopy);
};

template <typename Etype>
class Foo<Etype*>
{
public:
	Foo(Etype* param, short* param2);
	Foo(const Foo<Etype*>& toCopy);
};

template<typename Etype>
Foo<Etype>::Foo(Etype& param)
{
}

template<typename Etype>
Foo<Etype>::Foo(const Foo<Etype>& toCopy)
{
}

template<typename Etype>
Foo<Etype*>::Foo(Etype* param, short* param2)
{
}

template<typename Etype>
Foo<Etype*>::Foo(const Foo<Etype*>& toCopy)
{
}

Code: Alles auswählen

Foo<float*>(NULL, 0);
-> kompiliert

Code: Alles auswählen

Foo<const float*>(NULL, 0);
-> kompiliert

Code: Alles auswählen

Foo<float* const>(NULL, 0);
-> C2661 "no overloaded function takes 2 arguments"

Code: Alles auswählen

Foo<const float* const>(NULL, 0);
-> C2661 "no overloaded function takes 2 arguments"

Könnt ihr mir sagen, warum ich keine konstanten Pointer übergeben kann?
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Style - class template specializations && one class per

Beitrag von CodingCat »

Kannst du, aber damit landest du nicht mehr in der Spezialisierung, weil du jetzt klar konstante Zeiger als "Werte" hast. Prinzipiell lässt sich das durch eine weitere Spezialisierung für T *const lösen, was mir hier jedoch wenig sinnvoll erscheint. Tatsächlich würde ich so weit gehen, zu postulieren, dass eine Spezialisierung für konstante Zeiger darauf hinweist, dass schon die Spezialisierung für Zeiger nicht der richtige Weg war. Da ich jedoch wieder nur raten kann, hier unabhängig von dessen Sinnhaftigkeit im konkreten Fall trotzdem ein Lösungsansatz zur arbeitseffizienten Spezialisierung:

Code: Alles auswählen

template <class T>
class ActualFunctionality { ... };
template <class T>
class ActualFunctionality<T*> { ... };
template <class T>
class Template : public ActualFunctionality< typename remove_const<T>::type > { Delegating Constructors ... };
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: Style - class template specializations && one class per

Beitrag von kaiserludi »

CodingCat hat geschrieben: Tatsächlich würde ich so weit gehen, zu postulieren, dass eine Spezialisierung für konstante Zeiger darauf hinweist, dass schon die Spezialisierung für Zeiger nicht der richtige Weg war.
Oder dass versucht wird, bis zur weiten Unterstützung von C++ 11 auf C++ 11 Features wie Movement Semantics zu verzichten?
Ein wirklicher Spezialbehandlungsbedarf für pointer läge nicht vor, wenn ich sicherstellen könnte, dass alle Compiler, die wir je unterstützen wollen, Movement Sematics unterstützen, aber nachdem ich den Code schon auf Plattformen zum lafuen bekommen musste, die nicht nur keine C++ Standard Library und die C Standard lib nur teilweise kannten, sondern auch keine namespaces, keine Templates, quasi keienrlei C++ 03 Support, warte ich lieber noch ein wenig mit C++ 11 Features im Code. Auch removeConst wird bei Bedarf selb definiert werden, wenn auch im namespace, um Konflikten vorzubeugen.
CodingCat hat geschrieben: Da ich jedoch wieder nur raten kann
Sorry, aber das Projekt ist größtenteils Closed Source, weshalb ich manchmal etwas unkonkreter bleiben muss, als mir lieb ist, wenn ich nicht jedem Leser hier erst ein NDA unter die Nase halten will, und außerdem wird es dich wohl auch nicht begeistern, wenn ich hier tausende Zeilen Code poste, damit der Zusammenhang deutlich wird, warum das Interface welcher Klasse was ermöglichen muss, warum andere Kalssen das widerum brauchen, etc. Davon ab interessiert mich eben auch die Frage im Allgemeinen unabhängig vom konkreten Anwendungsfall.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Style - class template specializations && one class per

Beitrag von CodingCat »

kaiserludi hat geschrieben:
CodingCat hat geschrieben: Tatsächlich würde ich so weit gehen, zu postulieren, dass eine Spezialisierung für konstante Zeiger darauf hinweist, dass schon die Spezialisierung für Zeiger nicht der richtige Weg war.
Oder dass versucht wird, bis zur weiten Unterstützung von C++ 11 auf C++ 11 Features wie Movement Semantics zu verzichten?
Auch dann wären ein Adapter oder interne Delegation wohl bessere Lösungen, wobei du bei der internen Delegation wieder in abgewandelter Form das Muster meines vorangegangenen Posts nutzen könntest, um die zusätzliche Spezialisierung für T *const loszuwerden:

Code: Alles auswählen

template <class E, class T> struct PointerValueStuff { ... };
template <class E, class T> struct PointerValueStuff<E*, T> { ... };
template <class T> struct MyTemplate
{
 // Delegate stuff to PointerValueStuff<typename remove_const<T>::type, T>::...
};
kaiserludi hat geschrieben:Sorry, aber das Projekt ist größtenteils Closed Source, weshalb ich manchmal etwas unkonkreter bleiben muss, als mir lieb ist, wenn ich nicht jedem Leser hier erst ein NDA unter die Nase halten will, und außerdem wird es dich wohl auch nicht begeistern, wenn ich hier tausende Zeilen Code poste, damit der Zusammenhang deutlich wird, warum das Interface welcher Klasse was ermöglichen muss, warum andere Kalssen das widerum brauchen, etc.
Meistens ist der Zusammenhang aber eben absolut entscheidend für den richtigen Lösungsansatz. Was dein Code schlussendlich konkret tut, ist mir vollkommen gleich, trotzdem wirst du doch eine sehr abstrakte Beschreibung des grundsätzlichen Problems geben können.
Bei einem Container würde sich beispielsweise die grundsätzliche Frage stellen, was die Übergabe konstanter Typen überhaupt bedeuten soll; im Regelfall würde ich diese dort einfach verbieten.
kaiserludi hat geschrieben:Davon ab interessiert mich eben auch die Frage im Allgemeinen unabhängig vom konkreten Anwendungsfall.
Deshalb habe ich sie ja trotzdem auch noch allgemein beantwortet.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: Style - class template specializations && one class per

Beitrag von kaiserludi »

Ja. Da hast du wohl recht.

Zum Themas konstante Typen:
Ich sehe keinen Sinn darin, den User dazu zu zwingen, erst ein const weg zu casten, wenn der Container eh nur Lesezugriff und das Überschreiben der einmal gespeicherten Daten mit neuen erlaubt, aber keine Änderung vorhandener Userdaten, auch übergebener Pointer, auf neue Werte.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: Style - class template specializations && one class per

Beitrag von kaiserludi »

CodingCat hat geschrieben:Kannst du, aber damit landest du nicht mehr in der Spezialisierung, weil du jetzt klar konstante Zeiger als "Werte" hast.
Was mir dabei noch nicht klar ist: Warum lande ich bei konstanten Pointern nicht in der Pointer Spezialiserung, aber bei Pointern auf Konstanten schon? Bei letzteren geht doch die const-Information für den Wert, auf den der Zeiger zeigt, genauso verloren, wie bei ersteren die const-Info über den Zeiger selbst.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Style - class template specializations && one class per

Beitrag von CodingCat »

kaiserludi hat geschrieben:Was mir dabei noch nicht klar ist: Warum lande ich bei konstanten Pointern nicht in der Pointer Spezialiserung, aber bei Pointern auf Konstanten schon? Bei letzteren geht doch die const-Information für den Wert, auf den der Zeiger zeigt, genauso verloren, wie bei ersteren die const-Info über den Zeiger selbst.
Inwiefern das? In letzterem Fall landest du mit const X* in der Spezialisierung für T * mit T = const X, die const-Information bleibt erhalten. Würdest du in ersterem Fall genauso in der Spezialisierung für T * landen, wäre hingegen T = X, ganz unabhängig davon, ob X* oder X *const übergeben wurde, die const-Information wäre also tatsächlich verloren.
kaiserludi hat geschrieben:Ich sehe keinen Sinn darin, den User dazu zu zwingen, erst ein const weg zu casten, wenn der Container eh nur Lesezugriff und das Überschreiben der einmal gespeicherten Daten mit neuen erlaubt, aber keine Änderung vorhandener Userdaten, auch übergebener Pointer, auf neue Werte.
Alle STL-Container erforder(te)n das, warum also deine eigenen extra kompliziert machen?

Nachtrag: Die MSVC++ 10 beiliegende STL erlaubt zwar die Angabe von konstanten Elementypen, ignoriert deren const-Qualifizier jedoch einfach.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: Style - class template specializations && one class per

Beitrag von kaiserludi »

CodingCat hat geschrieben:
kaiserludi hat geschrieben:Was mir dabei noch nicht klar ist: Warum lande ich bei konstanten Pointern nicht in der Pointer Spezialiserung, aber bei Pointern auf Konstanten schon? Bei letzteren geht doch die const-Information für den Wert, auf den der Zeiger zeigt, genauso verloren, wie bei ersteren die const-Info über den Zeiger selbst.
Inwiefern das? In letzterem Fall landest du mit const X* in der Spezialisierung für T * mit T = const X, die const-Information bleibt erhalten. Würdest du in ersterem Fall genauso in der Spezialisierung für T * landen, wäre hingegen T = X, ganz unabhängig davon, ob X* oder X *const übergeben wurde, die const-Information wäre also tatsächlich verloren.
Ah, OK. Dass bei const* dann T = const X und nicht T = X, bei *const aber nich, hatte ich nicht bedacht. Danke.
CodingCat hat geschrieben:
kaiserludi hat geschrieben:Ich sehe keinen Sinn darin, den User dazu zu zwingen, erst ein const weg zu casten, wenn der Container eh nur Lesezugriff und das Überschreiben der einmal gespeicherten Daten mit neuen erlaubt, aber keine Änderung vorhandener Userdaten, auch übergebener Pointer, auf neue Werte.
Alle STL-Container erforder(te)n das, warum also deine eigenen extra kompliziert machen?

Nachtrag: Die MSVC++ 10 beiliegende STL erlaubt zwar die Angabe von konstanten Elementypen, ignoriert deren const-Qualifizier jedoch einfach.
"warum also deine eigenen extra kompliziert machen"
Ich vertrete da den Ansatz "Warum solche Arbeit dem Nutzer einer Lib/API/Klasse aufbürden, welche diese selbst bereits übernehmen kann". In dem Fall heißt das "Warum soll der Nutzer des Containers bei jedem Aufruf im Code, bei dem er einen *const verwendet, casten müssen, wenn die Implementation des Containers das auch zentral an einer Stelle erledigen kann".
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Style - class template specializations && one class per

Beitrag von CodingCat »

Wo muss der Benutzer denn casten? Schreibt der Benutzer wirklich permanent Templates mit Typdeduktion?
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Antworten