Menü
Avatar von pre alpha
  • pre alpha

757 Beiträge seit 13.05.2006

Re: Ist ja übel

iUniversEi schrieb am 18.02.2019 16:30:

pre alpha schrieb am 18.02.2019 15:56:

Es kann doch aber nicht sein, daß die Reihenfolge der Def/Impl über das Verhalten bestimmt.

Das ist doch aber immer so. Wie willst du es denn auch sonst machen? Kleinster Fixpunkt auf dem AST? Dann müsstest du aber garantieren, dass spätere alle Deklarationen die Semantik monoton ändern, sonst gibt's diesen Fixpunkt vielleicht gar nicht (im worst case terminiert Kompilierung dann nie).

Entscheidend ist immer die Reihenfolge der Deklaration, wo die Definitionen stehen ist i.A. egal (diese brauchen nichtmal sichtbar sein, weil sie später reingelinkt werden).

??? Habs jetzt doch mal durchexerziert:

// T* zuerst template <typename T> struct NamePerTemplateParameter1 { std::string getTypeName() {return "unknown"; } }; template <typename T> struct NamePerTemplateParameter1<T*> { std::string getTypeName() {return "pointer"; } }; template <> struct NamePerTemplateParameter1<int*> { std::string getTypeName() {return "int pointer"; } }; // int* zuerst template <typename T> struct NamePerTemplateParameter2 { std::string getTypeName() {return "unknown"; } }; template <> struct NamePerTemplateParameter2<int*> { std::string getTypeName() {return "int pointer"; } }; template <typename T> struct NamePerTemplateParameter2<T*> { std::string getTypeName() {return "pointer"; } }; // T* zuerst struct NamePerMethod1 { template <typename T> std::string getTypeName(T) {return "unknown"; } template <typename T> std::string getTypeName(T*) {return "pointer"; } std::string getTypeName(int*) {return "int pointer"; } }; // int* zuerst struct NamePerMethod2 { template <typename T> std::string getTypeName(T) {return "unknown"; } std::string getTypeName(int*) {return "int pointer"; } template <typename T> std::string getTypeName(T*) {return "pointer"; } }; int main() { int *p=nullptr; NamePerTemplateParameter1<decltype(p)> n0; NamePerTemplateParameter2<decltype(p)> n1; NamePerMethod1 n2; NamePerMethod2 n3; std::cout<<n0.getTypeName()<<std::endl; std::cout<<n1.getTypeName()<<std::endl; std::cout<<n2.getTypeName(p)<<std::endl; std::cout<<n3.getTypeName(p)<<std::endl; return 0; }

Das funktioniert zuverlässig - wobei in den NamePerMethod getTypeName(int*) kein Template mehr ist. Herr Grimm schrieb ja auch den Grund dazu:

Der Grund für dieses, nicht so intuitive Verhalten ist, dass Funktionsüberladung Template-Spezialisierung ignoriert.

Also: mit Klassen/Methoden geht's, mit Funktionen geht's nicht.
Dieses Verhalten mag zwar definiert sein, ist aber wie gesagt mMn ein Sprachdefekt.

Du hast natürlich recht, dass unachtsame Benutzung zu Problemen führen können. Deshalb führen die Core Guidelines diese Regel auch an, dass man sowas lieber nicht programmieren sollte. Allerdings kommt diese Regel eher als eine Art Kindersicherung daher, da sie viel mehr "verbietet", als nötig wäre, um dem Problem aus dem Weg zu gehen.

Richtig. Schön daß hier vor diesem Bug gewarnt wurde. Ich kannte ihn noch nicht.

Ohne das Böse zu meinen, ist C++ eben für den Durchschnittsprogrammierer einfach zu kompliziert. Daher versuchen solche Guidelines eben eine Art "Subset von C++" zu definieren, der Safe for Work ist. Leider werden manche coolen Features dabei etwas zu stark dämonisiert, sodass dann leicht der Eindruck entsteht, da wäre was mit der Sprache nicht in Ordnung.

Ich mag die ganzen heftigen Features :-)

Bewerten
- +
Anzeige