Pointer to data member "casten"?



  • Okay, mal wieder ein lustiges Problem!

    Sagen wir, es gibt:

    class A {};
    class B : public A {};
    
    class User {
       B some;
    };
    

    Jetzt ist &User::some ja vom Typ B (User::);
    Gibt es irgendwie einen Weg diesen Pointer-to-member in A (User::
    ) zu casten? Also dass ich über den Offset der dahinter steckt direkt auf die Basisklasse zugreifen kann und vor allem diese Zeiger in einem Array abspeichern kann?



  • Ich sollte anmerken, dass ich im Visual Studio CTP 2015 den cast versucht habe, aber der sagte mir, dass "B" nicht in "A User::*" konvertiert werden kann. Nun glaube ich Visual Studio oftmals nicht, außerdem ist der Typ "B" in der Fehlermeldung einfach falsch, also vertut sich entweder die Fehlermeldung oder mein Code ist einfach falsch. Ich könnte da auch ein simpel-Beispiel draus destillieren, falls der Cast ansonsten gültig wäre in C++.



  • Die Fehlermeldung lautet genau:

    error C2440: 'static_cast': cannot convert from 'up::bindings::integer_t<Access> ' to 'up::detail::dynamic_binding_base sample_struct::*
    

    Der Quelltyp ist aber "up::bindings::integer_t<Access> sample_struct::*", wobei "up::bindings::integer_t<Access>" öffentlich von "up::detail::dynamic_binding_base" ableitet.



  • Na gut, nur schnell mal das Beispiel, das ich da gegeben habe, ausprobiert:

    error C2440: 'initializing': cannot convert from 'B User::* ' to 'A User::* '
    

    Die Konvertierung scheint also einfach nicht erlaubt zu sein, ja? Schade eigentlich... Ständig Steine im Weg mit C++...

    Das einzige funktionsfähige, das ich jetzt habe ist, die Teile in unterschiedlichem Typ in einem std::tuple zu lagern und indizierten Zugriff mit einer linearen Suche (if( idx == 0 ) {...} else if {idx == 1) {...} else if ..." durchzuführen und die Konvertierung auf dem dereferenzierten Zeiger durchzuführen... Dabei ist das doch einfach ein blöder Offset, verdammt nochmal.


  • Mod

    Diese Art von Konvertierung ist nicht vorgesehen.

    decimad schrieb:

    Dabei ist das doch einfach ein blöder Offset, verdammt nochmal.

    Solange keine virtuellen Basen im Spiel sind oder garantiert ist, dass Pointer auf Member immer auf ein most-derived-Objekt zeigen. Letzteres würde nicht mehr zutreffen, wenn die Konvertierung zulässig wäre. Ersteres könnte man explizit ausschließen, wenn man die Sprache entsprechend erweitern wollte.

    Wenn du ein bisschen mehr Kontext gibst, findet sich evtl. eine andere Lösung?



  • Hallo camper!

    Also Quell des Problem ist, dass ich gerade ausprobiere, was ich so an statischen Konstrukten für die komfortable Adaptierung bei Reflektion bereitstellen kann.

    class some {
    
        INTEGRAL_METHOD_BINDER(get_something, set_something) something_binder;
        static const char something_id[];
    
        static_id_group< my_class,
             group_descriptor< something_id, decltype(&my_class::something_binder), &my_class::something_binder >
        > root_group;
    }
    

    Diese Root-Group bekommt jetzt also eine variable Anzahl von group_descriptor-Templates mit Member-Zeigern, die alle zu einer Basisklasse konvertiert werden "könnten". static_id_group stellt dann eine Schnittstelle bereit, mit der man per Index den Zeiger auf diese Basisklassen bekommt, also:

    template< const char* Id, typename PtrType, PtrType Ptr >
    	struct group_descriptor
    	{
    		template< typename T >
    		static binding access(T* cls) {
    			// Konvertierung auf konkreter Instanz...
    			return binding( &(cls->*Ptr), false );
    		}
    	};
    
    	namespace detail {
    
    		// Rekursiver lookup -.-
    		template< typename TupleType, typename Class, unsigned int TupleSize, unsigned int Index >
    		struct dynamic_tuple {
    			static binding get_binding(TupleType& tuple, Class* ptr, unsigned int idx) {
    				if (idx == Index) {
    					return std::get<Index>(tuple).access(ptr);
    				} else {
    					return dynamic_tuple<TupleType, Class, TupleSize, Index + 1>::get_binding(tuple, ptr, idx);
    				}
    			}
    		};
    
    		template< typename TupleType, typename Class, unsigned int TupleSize >
    		struct dynamic_tuple< TupleType, Class, TupleSize, TupleSize > {
    			static binding get_binding(TupleType& tuple, Class* ptr, unsigned int idx) {
    				return binding(nullptr, false);
    			}
    		};
    
    	}
    
    	template< typename Class, typename... Descriptors >
    	struct static_id_group : public id_group {
    		static_id_group(Class* ptr)
    			: ptr_(ptr)
    		{}
    
    		std::size_t num_bindings() const override {
    			return sizeof...(Descriptors);
    		}
    
    		binding get_binding(std::size_t idx) {
    			std::tuple< Descriptors... > tuple;
    			return detail::dynamic_tuple<decltype(tuple), Class, sizeof...(Descriptors), 0>::get_binding(tuple, ptr_, idx);	
    			//return binding( &(ptr_->*elements[idx].Ptr), false );	// Das wäre schön!
    		}
    
    		const char* binding_name() const override {
    			return "id_group";
    		}
    
    		const type_info& get_binding_info() const override {
    			return typeid(id_group);
    		}
    
    	private:
    		struct elem {
    			const char* name;
    			up::detail::dynamic_binding_base(Class::*Ptr);
    		};
    
    		// static elem elements[]; // Schade :(
    		Class* ptr_;
    	};
    
    	/* Geht leider nicht
    	template< typename Class, typename... Descriptors >
    	typename static_id_group<Class, Descriptors...>::elem static_id_group<Class, Descriptors...>::elements[] =
    	{
    		{ "", static_cast<up::detail::dynamic_binding_base (Class::*)>(Descriptors::ptr)}...
    	};
    	*/
    

    Während das Tuple-Konstrukt "funktioniert", aber eben diese if-else-Kette erzeugt (Man müsste mal überprüfen ob der Compiler begreift, dass hier im Prinzip ein "zusammenhängender" Lookup stattfindet), statt direkt einen Zeiger aus einem Feld zu fischen, bekomme ich das Konstrukt mit dem Array leider nicht zum kompilieren und mir fällt da auch kein Workaround ein.

    Ich möchte also im Prinzip -> pro Klasse <- ein Array anlegen, mit dem man per Instanz-Zeiger und Index an die Schnittstellen herankommt.



  • Achso, bitte entschuldige die Namen, oder dass einige Member in den kommentierten Sektionen nicht mehr existieren. Das war die letzten Minuten sehr im Fluss 😉


Log in to reply