ADL und Rückgabewerte
-
Hallo,
bekannt ist ja z.B. der folgende ADL-Trick mit
swap:template<typename T> void Swap(T& Lhs, T& Rhs) { using std::swap; swap(Lhs, Rhs); }Natürlich gibt ein
swapeigentlich nichts zurück, das soll nun aber nur stellvertretend stehen für jede beliebige Funktion, die etwas zurückgibt und diesen ADL-Trick benutzt.
Die Frage ist nun jedoch, wie dasselbe Lookup-Verhalten beim Rückgabetypen in C++03 erreicht werden kann. In C++11 habe ich es (quick 'n' dirty) hinbekommen (ich frage mich jedoch was geschieht / geschehen sollte, wenn jemandstd::swapin den globalen Namensraum holt):template<typename T> struct HasCustomSwap { template<typename U> static al::TrueType Check(decltype(swap(std::declval<T>(), std::declval<T>()))*); template<typename U> static al::FalseType Check(...); static const bool Value = sizeof(Check<T>(0)) == sizeof(al::TrueType); }; template<typename T, bool Custom = HasCustomSwap<T>::Value> struct SwapRet; template<typename T> struct SwapRet<T, true> { typedef decltype(swap(std::declval<T>(), std::declval<T>())) Type; }; template<typename T> struct SwapRet<T, false> { typedef void Type; // Der Rückgabetyp von std::swap }; template<typename T> typename SwapRet<T>::Type SwapClone(T& Lhs, T& Rhs) { using std::swap; return swap(Lhs, Rhs); }Und wenn ich schon einen Thread aufgemacht habe, dann noch gleich was anderes:
Wie kann ich den folgenden trivialen C++11-Code nach C++03 umschreiben?template<typename ContainerT> struct BeginT { typedef decltype(std::declval<ContainerT>().begin()) Type; };Ich habe daran rumgebastelt aber bin leider nicht vom Fleck gekommen.
Gruss
-
template<typename ContainerT> struct BeginT { typedef typename ContainerT::iterator Type; };? :p
-
Dann vermutlich schon eher:
template<typename ContainerT> struct BeginT { typedef typename ContainerT::iterator Type; }; template<typename ContainerT> struct BeginT<const ContainerT> { typedef typename ContainerT::const_iterator Type; };
Das Problem ist jedoch, dass ich bei gewissen Container die Methodebegindefiniere (damit Range-Based-For-Loops funktionieren), der Rest (und somit auch die Iteratortypen) jedoch mein gewohntes PascalCase ist, womit diese Lösung dann leider nicht funktioniert.
Wenn es nicht geht, so könnte ich alternativ noch sowas wie ContainerTraits basteln, dann funktionieren aber z.B. Container aus Boost nicht ohne Weiteres.
-
asfdlol schrieb:
Wie kann ich den folgenden trivialen C++11-Code nach C++03 umschreiben?
template<typename ContainerT> struct BeginT { typedef decltype(std::declval<ContainerT>().begin()) Type; };Allgemeingültig wahrscheinlich gar nicht (begin könnte Defaultargumente haben). Praktisch ausreichend dürfte es sein, einfach &ContainerT::begin zu analysieren. Wenn begin pathologisch ist und einen Funktor darstellt, muss dann eben noch &ContainerT::begin::operator() untersucht werden. Hatten wir ja gerade erst.
-
camper schrieb:
Allgemeingültig wahrscheinlich gar nicht (begin könnte Defaultargumente haben). Praktisch ausreichend dürfte es sein, einfach &ContainerT::begin zu analysieren. Wenn begin pathologisch ist und einen Funktor darstellt, muss dann eben noch &ContainerT::begin::operator() untersucht werden. Hatten wir ja gerade erst.
Es geht konkret wirklich nur um
ContainerT::begin. Auf&ContainerT::beginbin ich auch schon gekommen, wie ich aber von einer Instanz des Methodenzeigers auf den Rückgabetypen dessen komme, ist mir schleierhaft.Du spielst vermutlich auf diesen Thread an. Ich habe jetzt auf die Schnelle nichts gesehen zum Auslesen des Rückgabetypen.
-
asfdlol schrieb:
camper schrieb:
Allgemeingültig wahrscheinlich gar nicht (begin könnte Defaultargumente haben). Praktisch ausreichend dürfte es sein, einfach &ContainerT::begin zu analysieren. Wenn begin pathologisch ist und einen Funktor darstellt, muss dann eben noch &ContainerT::begin::operator() untersucht werden. Hatten wir ja gerade erst.
Es geht konkret wirklich nur um
ContainerT::begin. Auf&ContainerT::beginbin ich auch schon gekommen, wie ich aber von einer Instanz des Methodenzeigers auf den Rückgabetypen dessen komme, ist mir schleierhaft.Der alte Spezialisierungstrick... , oh moment, geht ja nicht, wegen fehlden Varargs.
Edit: Fail, decltype gibts ja nicht.
Also nicht ganz allgemein:template <typename Fnc> struct get_return; template <typename R, typename C> struct get_return<R (C::*)()> { // using... oh, kein using, C++03 ist irgendwie Mist typedef R type; // ich glaub so rum... typedef hab ich schon ewig nicht mehr benutzt };
-
asfdlol schrieb:
wie ich aber von einer Instanz des Methodenzeigers auf den Rückgabetypen dessen komme, ist mir schleierhaft.
Mir auch. War nicht ganz bei der Sache. decltype ist ja nicht ganz zufällig in die Sprache aufgenommen worden.
-
Nathan schrieb:
template <typename Fnc> struct get_return; template <typename R, typename C> struct get_return<R (C::*)()> { // using... oh, kein using, C++03 ist irgendwie Mist typedef R type; // ich glaub so rum... typedef hab ich schon ewig nicht mehr benutzt };Und wie kann ich bei
Fncnun den Typen von&ContainerT::begineinsetzen? Braucht leider auch wiederdecltype.Edit:
camper schrieb:
decltype ist ja nicht ganz zufällig in die Sprache aufgenommen worden.
Naja, C++11 hat schon teilweise Sprachelemente eingeführt, die nur Syntax Sugar sind (mir fallen aus dem Stegreif gerade Range-Based-For-Loops und
autoein). Aber ich entnehme daraus, dassdecltypenicht dazugehört (dessen war ich mir schon ziemlich sicher) die Möglichkeit das in C++03 zu implementieren nicht besteht, was?
-
asfdlol schrieb:
Nathan schrieb:
template <typename Fnc> struct get_return; template <typename R, typename C> struct get_return<R (C::*)()> { // using... oh, kein using, C++03 ist irgendwie Mist typedef R type; // ich glaub so rum... typedef hab ich schon ewig nicht mehr benutzt };Und wie kann ich bei
Fncnun den Typen von&ContainerT::begineinsetzen? Braucht leider auch wiederdecltype.Jaja, sieh meinem Edit.
Edit:
camper schrieb:
decltype ist ja nicht ganz zufällig in die Sprache aufgenommen worden.
Naja, C++11 hat schon teilweise Sprachelemente eingeführt, die nur Syntax Sugar sind (mir fallen aus dem Stegreif gerade Range-Based-For-Loops und
autoein). Aber ich entnehme daraus, dassdecltypenicht dazugehört (dessen war ich mir schon ziemlich sicher) die Möglichkeit das in C++03 zu implementieren nicht besteht, was?Nein, aber gcc bspw. bietet ein typeof an.
-
asfdlol schrieb:
Naja, C++11 hat schon teilweise Sprachelemente eingeführt, die nur Syntax Sugar sind (mir fallen aus dem Stegreif gerade Range-Based-For-Loops und
autoein).Echt? Wie kann man das hier ohne
autoimplementieren?template <typename iter> auto sum(iter begin_, iter end_) -> typename std::remove_reference<decltype(*begin_)>::type { using T = decltype(sum(begin_, end_)); T tmp(0); while (begin_ != end_) { tmp += *begin_; ++begin_; } return tmp; }Glaube zwar mal gelesen zu haben dass man
autoimmer mit einem passendendecltypeersetzen kann, aber hier wüsste ich nicht wie. Deswegen würde ich schon sagen dasautomehr als Syntax Sugar ist, oder?
-
template <typename iter> typename std::remove_reference<decltype(*std::declval<iter>())>::type sum(iter begin_, iter end_)autoist im Übrigen nicht nur Syntaxzucker. Wie wollt ihr sonstauto x = []{};schreiben?
-
Ok, wieder was gelernt

-
Diese
auto f() -> decltype()-Geschichte ist AFAIK auch nur Syntaxzucker (Vermeidung von Redundanz), berichtige mich bitte einer wenn ich falsch liege. Das Hauptargument dafür war ja dass man Bereichsauflösungen nicht mehr angeben muss und dass man sich auf die Argumente beziehen kann. Ersteres dürfte mit ausschreiben möglich sein (mir fällt im Moment kein Fall ein bei dem das nicht geht, habe aber irgendetwas mit verschachtelten Klassentemplates dazu im Hinterkopf) und letzteres mitstd::declval(was natürlich auch in C++03 implementierbar ist).Arcoth schrieb:
autoist im Übrigen nicht nur Syntaxzucker. Wie wollt ihr sonstauto x = []{};schreiben?
Hoppla, ja an Lambdas hab ich nicht gedacht, da hast du recht.
An die TMP-Pros hier:
Sind Variadic Templates Syntaxzucker wenn man von beliebig grossen Typlisten ausgeht?
-
asfdlol schrieb:
An die TMP-Pros hier:
Sind Variadic Templates Syntaxzucker wenn man von beliebig grossen Typlisten ausgeht?Jein.
Wenn man so etwas wie Alexandrescus Typelist hat mit beliebiger Anzahl an Erstellungsmakros kann man afaik alle Algorithmen auf Listen von Typen und so Dinge wie Tuples implementieren.
Was dann aber fehlt sind eine variable Anzahl an Parametern. Man muss dafür Tuple nehmen. Und auch Spezialisierungen für jede beliebige Funktion gehen dann nicht:template <typename R, typename ... Arg> struct foo<R(Arg...)> // wie ohne variadic templates?Man muss das dann wieder für jede Anzahl an Argumenten spezialisieren.
Wenn man das aber außen vorlässt, dann ja, sind sie nur Syntaxzucker, allerdings einer von der Sorte, der sehr viel Redunanz spart.
-
Arcoth schrieb:
autoist im Übrigen nicht nur Syntaxzucker. Wie wollt ihr sonstauto x = []{};schreiben?
Moment, also das hier geht auch ganz ohne
auto:using lambda = void(*)(); lambda x = []{};Also doch nur (sehr nützlicher) Syntax Sugar?
-
happystudent schrieb:
Arcoth schrieb:
autoist im Übrigen nicht nur Syntaxzucker. Wie wollt ihr sonstauto x = []{};schreiben?
Moment, also das hier geht auch ganz ohne
auto:using lambda = void(*)(); lambda x = []{};Also doch nur (sehr nützlicher) Syntax Sugar?
Ja, aber sobald du etwas captures (?), gehts nicht mehr.
-
Nathan schrieb:
Ja, aber sobald du etwas captures (?), gehts nicht mehr.
Hm, wie wärs dann mit:
std::function<void(void)> x = [=]{};?
Das geht bei mir auf jeden Fall...
-
Ja, aber sobald du etwas captures (?), gehts nicht mehr.
Stimmt schon, darauf wollte ich auch hinaus. Wenn du etwas capturest bekommt das closure-Objekt ja einen State.
Ich meine mich zu erinnern dass camper erwähnt hat dass
autoursprünglich für Lambdas eingeführt wurde.Sind Variadic Templates Syntaxzucker wenn man von beliebig grossen Typlisten ausgeht?
Wie willst du ein Lambda eine variable Anzahl von Argumenten nehmen lassen?
[] (auto&&... a) {return f( std::forward<decltype(a)>(a)... );}Bei gewöhnlichen Funktionstemplates oder Klassentemplates kann man zwar für jede Länge explizit spezialisieren, ist aber auch verdammt hässlich.
-
Hm, wie wärs dann mit:
[..]Ist viel langsamer. Wenn du dann noch das Objekt an ein Funktionstemplate übergibst (wie
std::copy_ifo.ä.), wird es deutlich lahmer, weil ständig der Umweg überfunctiongemacht wird.
-
Arcoth schrieb:
Ist viel langsamer. Wenn du dann noch das Objekt an ein Funktionstemplate übergibst (wie
std::copy_ifo.ä.), wird es deutlich lahmer, weil ständig der Umweg überfunctiongemacht wird.Hm, Ok.
Aber eigentlich ist ein Lambda ja auch nur Syntax Sugar weil man sich ja genausogut (und trivial) immer einen Functor mit der selben Funktionalität bauen kann.
Also braucht man
autoeigentlich nur dann zwingend (= für nicht-Syntax Sugar) wenn man wiederum Syntax Sugar (nämlich ein Lambda) benutzen will. Somit wäreautowiederum selbst nur Syntax Sugar.Oder?