Template-Tricks
-
dot schrieb:
Im Gegensatz zu der von dir vorgeschlagenen Syntax, überprüft der Code aus dem OP, ob eine Klasse von einer konkreten Instanz eines konkreten Template abgeleitet ist.
Nein. Es prüft ob die Klasse von einer beliebigen instanz abgeleitet ist. Der Compiler ist nur smart genug zu bestimmen, welche möglicheen instanzparameter dafür in betracht kommen.
Semantisch ist das Ding: "ist X von einem Foo<T> mit beliebigem T abgeleitet"?
Und Decimad hängt sich zurecht daran auf, dass der Ansatz nicht auf beliebige Foo generalisierbar ohne für jedes Foo einen konkreten Satz an Funktionen/Klassen zu verwenden. Und ja, das ist Schade und eine Schwäche des Typsystems, denn ich verwende "is_base_of" fast nie, im Gegensatz zu einem "is_derived_from_some_arbitraryFooT"//edit um Konstruktiv zu sein Keine Ahnung ob das compiliert, müsste aber gehen:
template<class T, class template<class> Foo> struct is_derived_from_unary_arg_template_base { template<class H> yes_t test(const Foo<H>&); no_t test(...); static const T& t; BOOST_STATIC_CONSTANT(bool, value = sizeof(test(t)) == sizeof(yes_t)); typedef boost::mpl::bool_<value> type; }; template<class H> class Foo{}; class Bar:public Foo<int>{}; is_derived_from_unary_arg_template_base<Bar, Foo>::valueinteressant wirds dann aber herauszufinden, welches Foo<H> es genau ist...
-
Hrmm, ja, erstmal Danke Otze dass Du so nett bist, dass ich mir hier nicht komplett blöde vorkommen muss. Irgendwann wird es bei mir wohl mit den Namen auch mal besser, hoffentlich.
Ich probiere das mal aus. Sieht auf den ersten Blick auf jeden Fall so aus, dass man besser versteht, was das ganze eigentlich machen soll!
-
otze schrieb:
dot schrieb:
Im Gegensatz zu der von dir vorgeschlagenen Syntax, überprüft der Code aus dem OP, ob eine Klasse von einer konkreten Instanz eines konkreten Template abgeleitet ist.
Nein. Es prüft ob die Klasse von einer beliebigen instanz abgeleitet ist. Der Compiler ist nur smart genug zu bestimmen, welche möglicheen instanzparameter dafür in betracht kommen.
Ich meinte natürlich, dass eine Klasse nur von einer konkreten Instanz abgeleitet sein kann. Die Lösung aus dem OP bestimmt, ob eine konkrete Klasse von einer Instanz eines Template abgeleitet ist und wenn ja von welcher (diese Information wird in weiterer Folge lediglich wieder weggeworfen).
otze schrieb:
Semantisch ist das Ding: "ist X von einem Foo<T> mit beliebigem T abgeleitet"?
Ja, aber dennoch kann X nur von einem Foo<T> abgeleitet sein und nicht von Foo, darum ging's mir.
otze schrieb:
Und Decimad hängt sich zurecht daran auf, dass der Ansatz nicht auf beliebige Foo generalisierbar ohne für jedes Foo einen konkreten Satz an Funktionen/Klassen zu verwenden.
#include <iostream> typedef char (&yes_t)[1]; typedef char (&no_t)[2]; template <typename T> T makeT(); template <template<typename ...> class B, typename... T> yes_t isBaseInstanceOf(const B<T...>&); template <template<typename ...> class B> no_t isBaseInstanceOf(...); template <template<typename ...> class B, typename D> struct is_base_instance_of { static bool value; }; template <template<typename ...> class B, typename D> bool is_base_instance_of<B, D>::value = sizeof(isBaseInstanceOf<B>(makeT<D>())) == sizeof(yes_t); template <typename T> struct A {}; template <typename T1, typename T2> struct B {}; struct C {}; struct D : public B<int, float> {}; int main() { std::cout << is_base_instance_of<A, D>::value << '\n'; std::cout << is_base_instance_of<B, D>::value << '\n'; //std::cout << is_base_instance_of<C, D>::value << '\n'; }Liefert zumindest unter clang auf den ersten Blick richtige Ergebnisse, nicht aber unter GCC und MSVC, bin mir noch nicht sicher, ob wohldefiniert...
-
Wobei man, wenn man es ganz genau sieht, es wohl
is_convertible_to_any_instance_of<Foo>
nennen müsste, oder nicht? Wird bei der Überladungssuche in Funktionstemplates noch die Konvertierungs-Operator-Maschinerie angeworfen?
-
Decimad schrieb:
Wobei man, wenn man es ganz genau sieht, es wohl
is_convertible_to_any_instance_of<Foo>
nennen müsste, oder nicht? Wird bei der Überladungssuche in Funktionstemplates noch die Konvertierungs-Operator-Maschinerie angeworfen?
Da hast du natürlich recht.
Wer selbst damit rumspielen möchte: http://liveworkspace.org/code/4tV60t$11
Edit: Auch möcht ich nochmal festhalten, dass es nicht meine Absicht war, irgendjemanden als dumm hinzustellen. Mir war anfangs tatsächlich nicht ganz klar, worauf Decimad hinaus wollte.
-
Decimad schrieb:
nennen müsste, oder nicht? Wird bei der Überladungssuche in Funktionstemplates noch die Konvertierungs-Operator-Maschinerie angeworfen?
das kann man aber umgehen:
das:
template<class H> yes_t test(const Foo<H>&); no_t test(...); static const T& t; BOOST_STATIC_CONSTANT(bool, value = sizeof(test(t)) == sizeof(yes_t));wird zu:
template<class H> yes_t test(Foo<H>*);//const weg, pointer her no_t test(...); T* createT(); BOOST_STATIC_CONSTANT(bool, value = sizeof(test(createT())) == sizeof(yes_t));
-
Nix geschehen. Zwar unterstützt mein Compiler leider noch keine Variadics, aber ich werde mal die Spezialisierungen für die 1-5 Parameter in meinen type_traits-Header aufnehmen. Ich finde, das würde sich auch ganz gut in Boost machen.
-
typedef char (&yes_t)[1]; typedef char (&no_t)[2]; template<typename T, template<typename> class ConvertibleTo> struct is_convertible_to_any_instance_of1 { private: template<class A1> static yes_t test(const ConvertibleTo<A1>&); static no_t test(...); static const T& t; public: static const bool value = sizeof(test(t)) == sizeof(yes_t); }; template< typename A1 > struct test_base1 { }; struct convertible1 { operator test_base1<int>(); }; int main(int argc, char* argv[]) { std::cout << is_convertible_to_any_instance_of1<convertible1,test_base1>::value << '\n'; return 0; }Gibt immer '0' aus. Habe ich da irgendeinen Fehler drin? Scheinbar werden die Konvertierungsoperatoren bei Template-Überladungen doch nicht mehr rausgesucht?
Edit: Auch wenn der operator richtigerweise als const definiert wäre.
-
dot schrieb:
Liefert zumindest unter clang auf den ersten Blick richtige Ergebnisse, nicht aber unter GCC und MSVC, bin mir noch nicht sicher, ob wohldefiniert...
Funktioniert ab gcc 4.7
-
Decimad schrieb:
Edit: Auch wenn der operator richtigerweise als const definiert wäre.
Dann mach ihn mal const. von einer const-referenz kann er nämlich nicht aufgerufen werden.
-
Also ich habe folgendes mit allen C++-Compilern durchprobiert:
http://liveworkspace.org/code/4tV60t$15
-
Decimad schrieb:
Also ich habe folgendes mit allen C++-Compilern durchprobiert:
http://liveworkspace.org/code/4tV60t$15Das war auch ohne Versuche klar.
Für einen Funktionsargument, das an Templateargumentdeduktion teilnimmt, werden fast alle impliziten Konvertierungen unterdrückt (bzw. umgekehrt versucht Argumentdeduktion eine Übereinstimmung zwischen formalem Funktionsparameter und tatsächlichem Argumnet beim Funktionsaufruf herzustellen - Ausnahmen siehe 14.2.8.1/4 - so dass eine zusätzliche Konvertierung nicht notwendig ist).
Ohne auf diese Feinheiten abzustellen muss aber klar sein, dass ein solches Prädikat nicht funktionieren kann. Die Frage, ob irgendeine Instantiierung eines Templates eine bestimmt Konvertierung unterstützt, ist äquvialent zu der, ob irgendeine Instantiierung über ein bestimmtes Member verfügt. Die einzige Möglichkeit, das zu festzustellen, ist, jede einzelne Variante zu instantiieren. Offensichtlich ist das nicht möglich, wenn die Anzahl der denkbaren Instantiierungen nicht von vornherein begrenzt ist.
-
Also Du kommst mir gerade knapp zuvor, ich habe anderweitig schon herausgelesen, was zu vermuten war: keine user-defined Konvertierung bei der template argument deduction. Diese Regel habe ich natürlich erst gerade gelernt.
In diesem speziellen Fall kann ich Deine Kritik an dem grundlegenden Gedanken, aber so nicht nachvollziehen, weil ja die echte Klasse "convertible1" bekannt ist , die auf "const test_base1<Arg1>&" gematched werden soll. Also sehe ich zumindest kein Kristallkugelproblem für den Compiler.
Wie dem auch sein. Aus diesem Grund ist also auch schon die Ausgangsversion mit den Referenzen für Benutzertypen ein "echtes" is_derived_from_any_instance_of, eben weil user-defined Konvertierungen gar nicht matchen können.
-
Decimad schrieb:
In diesem speziellen Fall kann ich Deine Kritik an dem grundlegenden Gedanken, aber so nicht nachvollziehen, weil ja die echte Klasse "convertible1" bekannt ist , die auf "const test_base1<Arg1>&" gematched werden soll. Also sehe ich zumindest kein Kristallkugelproblem für den Compiler.
Woher soll der Compiler wissen, dass es kein test_base1<X> mit einem Konvertierungskonstruktor für convertible1 gibt?
-
Das wären dann ja schon zwei verkettete implizite user-defined-Konvertierungen. Das lässt ja nichtmal die nicht-Template overload resolution zu, oder etwa doch? Heute ist wohl der Tag, an dem ich mangels echter Arbeit das meiste an Feinheiten von C++ lerne
Wenn die overload resolution das zulässt, dann habe ich das zumindest in meinem eigenen Code mit vollster Zufriedenheit noch nie ausgenutzt.
-
wieso verkettet? z.B.
template< typename A1 > struct test_base1 { }; struct convertible1 { operator test_base1<int>(); }; template <> struct test_base1<double> { test_base1(convertible1); };
-
Okay, in meinen Gedankengängen habe ich irgendwie nie solche Fälle erdacht, in denen die Template-Basisklasse schon abgelittene Klassen kennt, bzw. gleich noch durch sie konstruierbar ist. Irgendwie wäre das ja nicht is_convertible_to sondern eher is_constructible_from, oder? Naja, okay, ich sehe das Problem.