online compiler and debugger for c/c++

code. compile. run. debug. share.
Source Code   
Language
#include <cassert> #include <tuple> #include <vector> // Ich brauche ein Template (oder Tips) wie ich von einer Dispatcher-Klasse aus // ohne viel Boilerplate-Code native Methoden aufrufen kann // Das ganze Konzept funktioniert (schon etwas lC$nger) wie es soll // aber ich wC<rde sehr gerne den Boilerplate Code reduzieren // Hier ein stark vereinfachtes Beispiel - es geht mir in keinster Weise // um das Grundkonzept (das erkennt man in diesem Beispiel nicht wirklich) // sonder nur um ein bisschen Template-Magic in der // itest_class::test2_waere_perfekt Methode - der Rest-Code // ist nur damit meine Frage nicht total abstrakt ist // und man auch was ausfC<hren kann // mit up-to-date: VS2017 15.9.6 oder gcc 8.2, also (fast) alles was C++17 so hergibt struct i_value // Value-Schnittstelle fuer Konstanten,Expression,Referenzen,... { // INFO: Mein Framework stellt per Reflection-Prinzip magisch sicher das nur die selben Typen verbunden werden (void* ist bei mir 100% safe) virtual void set(const void* const value) = 0; virtual void get(void* const value) = 0; }; // hier in diesem Beispiel reduziere ich das ganze auf "Variablen" // also Objekte die das i_value Interface implementierung und einen Value-Zustand haben template<typename ValueType> struct value_t : i_value { ValueType _value = ValueType(); value_t(const ValueType& value) :_value(value) {} // hier ist normalerweise noch Absicherungs-Code drinn/dahinter/drumherum const ValueType& magical_safe_cast(const void* const value) const { return *reinterpret_cast<const ValueType*>(value); } ValueType& magical_safe_cast(void* value) { return const_cast<ValueType&>(static_cast<const value_t*>(this)->magical_safe_cast(value)); } void set(const void* const value) override { set(magical_safe_cast(value)); } void get(void* value) override { magical_safe_cast(value) = get(); } void set(const ValueType& value) { _value = value; } ValueType& get() { return _value; } }; // liefert den return-type einer Methode template <typename Return, typename Class, typename ... Parameter> Return get_return_type(Return(Class::*)(Parameter...)); // liefert die parameter-typen einer Methode template <typename Class, typename Return, typename... Parameter> std::tuple<Parameter...> method_args(Return(Class::*)(Parameter...)) { return std::tuple<Parameter...>(); } // kleine Abstraktion um in, out und inout Verhalten zu erzeugen template<typename ValueType> struct in_parameter_t { ValueType _native_value = ValueType(); i_value* _value = nullptr; in_parameter_t(i_value* value) :_value(value) {} void load() { _value->get(&_native_value); } void store() {} // nicht implementiert da IN ValueType& operator()() { return _native_value; } }; template<typename ValueType> struct out_parameter_t { ValueType _native_value = ValueType(); i_value* _value = nullptr; out_parameter_t(i_value* value) :_value(value) {} void load() {} // nicht implementiert da OUT void store() { _value->set(&_native_value); } ValueType& operator()() { return _native_value; } }; template<typename ValueType> struct inout_parameter_t { ValueType _native_value = ValueType(); i_value* _value = nullptr; inout_parameter_t(i_value* value) :_value(value) {} void load() { _value->get(&_native_value); } void store() { _value->set(&_native_value); } ValueType& operator()() { return _native_value; } }; // traits um aus den Methoden/Result-Typen den richtigen Adapter zu bekommen template<typename ValueType> struct parameter_type_t {}; template<> struct parameter_type_t<const int&> { using type = in_parameter_t<int>; }; template<> struct parameter_type_t<const int> { using type = in_parameter_t<int>; }; template<> struct parameter_type_t<const double&> { using type = in_parameter_t<double>; }; template<> struct parameter_type_t<const double> { using type = in_parameter_t<double>; }; template<> struct parameter_type_t<int&> { using type = inout_parameter_t<int>; }; template<> struct parameter_type_t<double&> { using type = inout_parameter_t<double>; }; // "native" classe von der ich Methoden per ueber die itest_class aufrufen will struct test_class { int value = 100; void test0() { return; } void test1(const int& x, const double& y) { return; } double test2(const int& x, const double& y, double& z) { double res = x + y; z = 10; return res; } int& test3() { return value; } }; using iparameter = std::vector<i_value*>; // "native" class Wrapper/Dispatcher // mein Framework erlaubt magisch-dynamisch das Aufrufen dieser Dispatch-Funktionen (mit ivalue Parametern) struct itest_class { test_class object; // liegt normalerweise wo anders // Stufe 0: alles von Hand, maximal unsicher (auch wenn ich mit Tricks hier Fehler erkenne) void test2_von_hand(const iparameter& parameter, i_value* const result) { assert(parameter.size() == 3); int x = 0; double y = 0.0; double z = 0.0; double res = 0.0; // load parameter[0]->get(&x); // IN parameter[1]->get(&y); // IN parameter[2]->get(&z); // INOUT // run res = object.test2(x, y, z); // store result->set(&res); //parameter[0]->set(&x); // nicht noetig da IN parameter //parameter[1]->set(&y); // nicht noetig da IN parameter parameter[2]->set(&z); } // hier habe ich versucht micht reflektiv an der nativen-Methode zu orientieren // weniger Fehler, aber zu viel Code - nur eine Blaupause fuer die wohl notwendigen // Template-Helper void test2_bisschen_besser(const iparameter& parameter, i_value* const result) { // die Methoden-Signatur abgreifen using native_parameter_types = decltype(method_args(&test_class::test2)); using native_return_type = decltype(get_return_type(&test_class::test2)); static_assert(!std::is_same<native_return_type, void>::value, "void fehlt noch"); assert(parameter.size() == std::tuple_size<native_parameter_types>::value); // diesen tuple muesste man doch zur kompilezeit generieren koennen, oder? using parameter_types_t = std::tuple < parameter_type_t<std::tuple_element<0, native_parameter_types>::type>::type, parameter_type_t<std::tuple_element<1, native_parameter_types>::type>::type, parameter_type_t<std::tuple_element<2, native_parameter_types>::type>::type >; // diese instanzen vielleicht in einem tupel halten - aber wie geht das? std::tuple_element<0, parameter_types_t>::type p0(parameter[0]); std::tuple_element<1, parameter_types_t>::type p1(parameter[1]); std::tuple_element<2, parameter_types_t>::type p2(parameter[2]); using res_t = out_parameter_t<native_return_type>; res_t res(result); // load - schoen homogen, kann man das zur kompilezeit expandieren? p0.load(); p1.load(); p2.load(); // run // https://cpppatterns.com/patterns/apply-tuple-to-function.html // laut diesem tutorial kann man methoden auch mit tupels aufrufen res() = object.test2(p0(), p1(), p2()); // wie koennte man native_return_type == void loesen? if constexpr? // store res.store(); // setzt was // schoen homogen, kann man das zur kompilezeit expandieren? p0.store(); // macht nichts p1.store(); // macht nichts p2.store(); // setzt was } void test2_waere_perfekt(const iparameter& parameter, i_value* const result) { //!!! //Ziel meine Frage: Wie kann ich so ein run_method Template implementieren um //mir den ganzen Boilerplate Code zu sparen // mein GefC<hl sagt mir das so ein Template moeglich sein muesste //run_method(&object, &test_class::test2, parameter, result); } }; int main() { // Dispatcher-Klasse instanzieren itest_class itest_object; value_t<int> x(11); // value by ref value_t<double> y(22.0); // value by ref value_t<double> z(44.0); // ref iparameter parameter{ &x, &y, &z }; value_t<double> result(0); result.set(0.0); z.set(0.0); itest_object.test2_von_hand(parameter, &result); assert(result.get() == 33.0); assert(z.get() == 10.0); result.set(0.0); z.set(0.0); itest_object.test2_bisschen_besser(parameter, &result); assert(result.get() == 33.0); assert(z.get() == 10.0); //result.set(0.0); //z.set(0.0); //itest_object.test2_waere_perfekt(parameter, &result); //assert(result.get() == 33.0); //assert(z.get() == 10.0); return 0; }

Compiling Program...

Command line arguments:
Standard Input: Interactive Console Text
×

                

                

Program is not being debugged. Click "Debug" button to start program in debug mode.

#FunctionFile:Line
VariableValue
RegisterValue
ExpressionValue