Nur bei bestimmten template-Parametern kompilieren
-
Hallo!
Ich habe mehrere Klassen a, b, ... die alle von einer Klasse small abgeleitet sind:
class small {}; class a : public small {}; class b : public small {}; // uswUnd ich habe mehrere Klassen A, B, ... die alle von einer Klasse huge abgeleitet sind:
class huge {}; class A : public huge {}; class B : public huge {}; // uswAußerdem habe ich eine template-Klasse foo, die eine Methode operator= besitzt:
template<class T> class foo { public: foo<T> &operator=(foo<T> &f) {} };Nun soll eine Zuweisung genau dann kompilierbar sein, wenn beide template-Parameter von derselben Basisklasse abgeleitet wurden:
int main() { foo<a> fooa1, fooa2; foo<b> foob1; foo<A> fooA1; // ok fooa1 = fooa2; foob1 = fooa2; // !ok fooA1 = fooa2; return 0; }Wie könnte ich das realisieren?
Mfg
-
Falls es bei den beiden Basen small und huge bleibt, wäre dies ein Versuch wert:
#include <boost/utility/enable_if.hpp> #include <boost/type_traits/is_base_of.hpp> #include <boost/mpl/logical.hpp> template<class T> class foo { public: template< typename U > typename boost::enable_if< typename boost::mpl::or_< typename boost::mpl::and_< typename boost::is_base_of< T, small >, typename boost::is_base_of< U, small > >, typename boost::mpl::and_< typename boost::is_base_of< T, huge >, typename boost::is_base_of< U, huge > > >, foo<T>& >::type operator=( const foo<U>& f ) { return *this; } };Leider übersetzt er dann den Ausdruck
foob1 = fooa2;auch nicht, warum .. das habe ich noch nicht verstanden

:xmas2: Werner
-
ja, das grundsätzliche problem ist, dass man die basisklassen kennen müsste. oder der klassenhierarchie irgendwie informationen über ihre vererbungshierarchie mitgeben. aber das ist beides nicht ganz sauber.
hier auch ein relativ hässlicher workaround von mir:
#define CHECK_BASE(base)template <class U> \ foo &assign_check (foo<U> const &f, base*, base*) \ { return do_assign (f); } template<class T> class foo { public: foo &operator=(foo const &f) { return *this; } template <class U> foo &operator=(foo<U> const &f) { assign_check (f, static_cast<T*>(0), static_cast<U*>(0)); } private: CHECK_BASE (small) CHECK_BASE (huge) template <class U> foo &do_assign (foo<U> const &f) { //... return *this; } };
-
Werner Salomon schrieb:
Leider übersetzt er dann den Ausdruck
foob1 = fooa2;auch nicht, warum .. das habe ich noch nicht verstanden

:xmas2: WernerWeil du die Templateargumente vertauscht hast
sind auch ein paar typenames zuviel:template<typename T> class foo { typedef typename boost::mpl::if_< boost::is_base_of< small, T >, small, typename boost::mpl::if_< boost::is_base_of< huge, T >, huge, void >::type >::type base; public: foo(); template<typename U> foo(const foo<U>&, typename boost::enable_if< boost::is_base_of< base, U > >::type* = 0); };Wenn man noch mehr Basisklassen hat, wäre eine extra Metafunktion sinnvoll, um das ganz nicht in verschachtelten if_s zu ersticken.
-
Vielen Dank! :xmas1: