From 7e1019fbe6924e1d7771c7486a9c9b00904a342f Mon Sep 17 00:00:00 2001 From: Alexander Kulikov Date: Sun, 16 Feb 2020 13:45:04 +0300 Subject: [PATCH 01/10] error as warning for better errors detection; --- .gitignore | 1 + CMakeLists.txt | 23 +++++++++++++++++++++++ include/chain_invoke.h | 1 - test/testMain.cpp | 2 +- 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 42afec2..b8b5430 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # CMake - https://github.com/github/gitignore/blob/master/CMake.gitignore +CMakeLists.txt.user CMakeCache.txt CMakeFiles CMakeScripts diff --git a/CMakeLists.txt b/CMakeLists.txt index 820a721..3ef513b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,29 @@ enable_testing() add_library(mil INTERFACE) +target_compile_options(mil + INTERFACE + + -Werror + + -Wall + -Wextra + -Wpedantic + + -Wcast-align + -Wcast-qual + -Wconversion + -Wctor-dtor-privacy + -Wenum-compare + -Wfloat-equal + -Wnon-virtual-dtor + -Wold-style-cast + -Woverloaded-virtual + -Wredundant-decls + -Wsign-conversion + -Wsign-promo +) + target_include_directories(mil INTERFACE $ diff --git a/include/chain_invoke.h b/include/chain_invoke.h index 9feded9..dd022de 100644 --- a/include/chain_invoke.h +++ b/include/chain_invoke.h @@ -146,7 +146,6 @@ using namespace msl; */ template constexpr auto operator<<(OpFx const & aFx) && { - using invoking_t = typename function_info::cl; return OwningInvokingStep{ aFx, obj }; } }; diff --git a/test/testMain.cpp b/test/testMain.cpp index 5925cdb..12fc97b 100644 --- a/test/testMain.cpp +++ b/test/testMain.cpp @@ -75,7 +75,7 @@ struct Object2 struct Object3 : public InstanceCounter { - void getObject2(Object2 * obj) { + void getObject2(Object2 * /*obj*/) { //std::cout << " getObject2 invoked!" << std::endl; } }; From 9d94ec12657b2ebe0a2bbad18026cc18d2c28e5f Mon Sep 17 00:00:00 2001 From: Alexander Kulikov Date: Sun, 16 Feb 2020 21:12:11 +0300 Subject: [PATCH 02/10] additional static asserts; --- include/chain_invoke.h | 12 ++++-- include/function_info.h | 96 ++++++++++++++++++++++++++++++----------- include/object_invoke.h | 12 +++--- test/testMain.cpp | 20 +++++++-- 4 files changed, 101 insertions(+), 39 deletions(-) diff --git a/include/chain_invoke.h b/include/chain_invoke.h index dd022de..d765679 100644 --- a/include/chain_invoke.h +++ b/include/chain_invoke.h @@ -67,10 +67,14 @@ using namespace msl; * @tparam Fx Type of the method */ template - struct OwningInvokingStep { - using tuple_t = typename function_info::stack_args; - using qalified_t = typename function_info::args; - using class_t = typename function_info::cl; + struct OwningInvokingStep { + using TFunctionInfo = function_info; + using tuple_t = typename TFunctionInfo::stack_args; + using qalified_t = typename TFunctionInfo::args; + using class_t = typename TFunctionInfo::cl; + + // not use dicrectly but in constructor have static assert + const TFunctionInfo function_info_; static constexpr size_t TUPLE_SIZE { std::tuple_size_v }; diff --git a/include/function_info.h b/include/function_info.h index 424bde4..15d3afb 100644 --- a/include/function_info.h +++ b/include/function_info.h @@ -53,8 +53,27 @@ namespace msl { >; }; + template + void checkThanRefOrPointer() + { + static_assert(((std::is_reference_v || std::is_pointer_v) && ...), "must be pointer or reference"); + } + } /* end of namespace detal */ +// this macro will be unded in this file +#ifdef MARCRO_CHECK_THAN_REF_OR_POINTER +#error "MARCRO_CHECK_THAN_REF_OR_POINTER already defined" +#endif +#define MARCRO_CHECK_THAN_REF_OR_POINTER(ClassName)\ + {\ + ClassName()\ + {\ + detail::checkThanRefOrPointer();\ + }\ + }; +// endmacro defrnition + /** * @brief The function info base definition * @@ -73,7 +92,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -86,7 +106,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -99,8 +120,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; - + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** * @brief The partial specialization for qualifiers @@ -112,7 +133,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -125,7 +147,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -138,7 +161,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -151,7 +175,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -164,7 +189,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -177,7 +203,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -190,7 +217,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -203,7 +231,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -216,7 +245,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -229,7 +259,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -242,7 +273,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -255,7 +287,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info\ +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -268,7 +301,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -281,7 +315,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -294,7 +329,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -307,7 +343,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -320,7 +357,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -333,7 +371,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -346,7 +385,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -359,7 +399,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -372,7 +413,12 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) + +#ifdef MARCRO_CHECK_THAN_REF_OR_POINTER +#undef MARCRO_CHECK_THAN_REF_OR_POINTER +#endif } /* end of namespace msl */ diff --git a/include/object_invoke.h b/include/object_invoke.h index ea831c3..cdbd7e1 100644 --- a/include/object_invoke.h +++ b/include/object_invoke.h @@ -38,6 +38,10 @@ * @note MIL - Metaprogramming Invoking Library */ namespace mil { +/** + * @brief detail component namespace + */ +namespace detail { /** * @brief The delayed invoke holds information about methods chain to * be invoked. Invokes it and passes the result into the invoker @@ -104,12 +108,6 @@ namespace mil { char const * m_tag; }; - - /** - * @brief detail component namespace - */ - namespace detail { - /** @{ */ /* first class meta-function */ /** @@ -210,7 +208,7 @@ namespace mil { using object_t = TObjectType; using acceptor_t = TResultAcceptor; - using delayed_invoke_t = delayed_invoke; + using delayed_invoke_t = detail::delayed_invoke; /** diff --git a/test/testMain.cpp b/test/testMain.cpp index 12fc97b..a9c9ab3 100644 --- a/test/testMain.cpp +++ b/test/testMain.cpp @@ -69,15 +69,26 @@ struct Object2 : public InstanceCounter { void getObject1(Object1 & obj) { // std::cout << " getObject1 invoked!" << std::endl; - (void)obj; + obj = obj_; } + + Object1 obj_; }; struct Object3 : public InstanceCounter { - void getObject2(Object2 * /*obj*/) { + void getObject2(Object2 * obj) { //std::cout << " getObject2 invoked!" << std::endl; + *obj = obj_; + } + + void testFail(int c) + { + c = 15; + std::cout << c << std::endl; } + + Object2 obj_; }; struct Serializer { @@ -101,7 +112,10 @@ constexpr mil::object_invoke invoke { mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("call1"), mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("call2"), mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("call3"), - mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("call4") + mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("call4"), + + // this case not compile. it is okay + //mil::delayedInvoke<&Object3::testFail>("call5") }; From e13a49e31032d7ae495527307010895616adf59a Mon Sep 17 00:00:00 2001 From: Alexander Kulikov Date: Mon, 17 Feb 2020 09:25:06 +0300 Subject: [PATCH 03/10] first version which can work with C++ getter; --- include/chain_invoke.h | 51 ++++++++++++++++++++++++++++++++++++----- include/function_info.h | 1 + include/object_invoke.h | 4 ++-- test/testMain.cpp | 24 +++++++++++++++---- 4 files changed, 68 insertions(+), 12 deletions(-) diff --git a/include/chain_invoke.h b/include/chain_invoke.h index d765679..968e41a 100644 --- a/include/chain_invoke.h +++ b/include/chain_invoke.h @@ -61,6 +61,21 @@ using namespace msl; } } + template + struct TypeSelector final + { + private: + using t1 = std::conditional_t>; + inline static constexpr bool is_ref = std::is_reference_v; + using no_ref_but_pointer = std::tuple>>; + using t2 = std::conditional_t, std::tuple>; + + public: + inline static constexpr bool have_agrs_value = have_agrs; + inline static constexpr bool is_ref_value = is_ref; + using type = std::conditional_t; + }; + /** * @brief The invoking step object, which also holds the tuple * @@ -69,15 +84,16 @@ using namespace msl; template struct OwningInvokingStep { using TFunctionInfo = function_info; - using tuple_t = typename TFunctionInfo::stack_args; + using ret_t = typename TFunctionInfo::ret; + inline static constexpr bool have_agrs = TFunctionInfo::args_count > 0; + using type_selector_t = TypeSelector; + using tuple_t = typename type_selector_t::type; using qalified_t = typename TFunctionInfo::args; using class_t = typename TFunctionInfo::cl; // not use dicrectly but in constructor have static assert const TFunctionInfo function_info_; - static constexpr size_t TUPLE_SIZE { std::tuple_size_v }; - tuple_t tuple; /** @@ -92,8 +108,15 @@ using namespace msl; */ template constexpr auto operator<<(OpFx const & aFx) && { - using invoking_t = typename function_info::cl; - return OwningInvokingStep{ aFx, std::get(tuple) }; + if constexpr (type_selector_t::have_agrs_value) + { + using invoking_t = typename function_info::cl; + return OwningInvokingStep{ aFx, std::get(tuple) }; + } + if constexpr (!type_selector_t::have_agrs_value && !type_selector_t::is_ref_value) + { + return OwningInvokingStep{ aFx, std::get<0>(tuple) }; + } } /** @@ -106,7 +129,16 @@ using namespace msl; explicit constexpr OwningInvokingStep(Fx const & aFx, Obj & obj) : tuple { } { - this->invokeImpl(std::make_index_sequence{}, aFx, obj); + if constexpr (type_selector_t::have_agrs_value) + { + static_assert(std::is_same_v, "must be one type"); + this->invokeImpl(std::make_index_sequence{}, aFx, obj); + } + if constexpr (!type_selector_t::have_agrs_value && !type_selector_t::is_ref_value) + { + static_assert(std::is_same_v, "must be one type"); + this->invokeImplWithret(aFx, obj); + } } private: /** @@ -117,8 +149,15 @@ using namespace msl; */ template constexpr void invokeImpl(std::index_sequence, Fx const & aFx, Obj & obj) { + static_assert(std::is_same_v, "must be one type"); (obj.*aFx)(conditionalAddressOf>(std::get(tuple))...); } + + template + constexpr void invokeImplWithret(Fx const & aFx, Obj & obj) { + static_assert(std::is_same_v, "must be one type"); + std::get<0>(tuple) = (obj.*aFx)(); + } }; /** diff --git a/include/function_info.h b/include/function_info.h index 15d3afb..9726602 100644 --- a/include/function_info.h +++ b/include/function_info.h @@ -46,6 +46,7 @@ namespace msl { using ret = Ret; using cl = Class; using args = std::tuple; + inline static constexpr size_t args_count = sizeof...(Args); using stack_args = std::tuple< std::remove_pointer_t< std::decay_t diff --git a/include/object_invoke.h b/include/object_invoke.h index cdbd7e1..ca5cbb6 100644 --- a/include/object_invoke.h +++ b/include/object_invoke.h @@ -100,12 +100,12 @@ namespace detail { /** * @brief Pointer to a concrete invoker specialization */ - invoker_ptr_t m_invokerPtr; + invoker_ptr_t m_invokerPtr = nullptr; /** * @brief Associated tag */ - char const * m_tag; + char const * m_tag = nullptr; }; /** @{ */ diff --git a/test/testMain.cpp b/test/testMain.cpp index a9c9ab3..a5fd7aa 100644 --- a/test/testMain.cpp +++ b/test/testMain.cpp @@ -59,10 +59,18 @@ struct Object1 : public InstanceCounter { void getValue(int & i) { // std::cout << " getValue invoked!" << std::endl; - static int ii { 11111 }; ii += 11111; i = ii; } + + int retGetValue() + { + std::cout << "retGetValue" << std::endl; + ii += 11111; + return ii; + } + + inline static int ii { 11111 }; }; struct Object2 @@ -72,6 +80,11 @@ struct Object2 obj = obj_; } + Object1 retObject1() const { + std::cout << " retObject1 invoked" << std::endl; + return obj_; + } + Object1 obj_; }; @@ -106,16 +119,18 @@ struct Serializer { }; - -constexpr mil::object_invoke invoke { +constexpr mil::object_invoke invoke { mil::useAcceptor(), mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("call1"), mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("call2"), mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("call3"), mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("call4"), - // this case not compile. it is okay + // this case not compile. it is okay because getters C style must accept only refs and pointers //mil::delayedInvoke<&Object3::testFail>("call5") + + //mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::retGetValue>("call6"), + mil::delayedInvoke<&Object3::getObject2, &Object2::retObject1, &Object1::retGetValue>("call7") }; @@ -123,6 +138,7 @@ int main() { Object3 obj {}; Serializer si; + //invoke.set_logger(std::function{[](const std::string& v){ std::cout << v << std::endl; }}); invoke(obj, si); return 0; From 8428f6170c065b9c5292565d83819673eb8cd571 Mon Sep 17 00:00:00 2001 From: Alexander Kulikov Date: Sat, 22 Feb 2020 18:15:05 +0300 Subject: [PATCH 04/10] review revision correction; --- include/chain_invoke.h | 69 +++++++++++++++++++++++++++++++++--------- test/testMain.cpp | 16 ++++++++-- 2 files changed, 68 insertions(+), 17 deletions(-) diff --git a/include/chain_invoke.h b/include/chain_invoke.h index 968e41a..2b4ae00 100644 --- a/include/chain_invoke.h +++ b/include/chain_invoke.h @@ -61,19 +61,48 @@ using namespace msl; } } + /** + * @brief TypeSelector will select what tuple of agrs will get from function + * tuple fow univsality and compatibility + * @tparam have_agrs have function atgs or no + * @tparam TRet return type + * @tparam stack_args tuple of args if function have_agrs + * @details Possible three variants which described below + // 1) if have agrs - then return type must be void and function params must + // be refs or pointers. Selected type is tuple (stack_args) + // 2) if have no agrs and return type is not ref or pointer then selected type is tuple + // 3) if have no agrs and return type is ref or pointer then selected type is tuple> + */ template struct TypeSelector final { private: - using t1 = std::conditional_t>; + using stack_args_or_ret_value = std::conditional_t>; inline static constexpr bool is_ref = std::is_reference_v; + inline static constexpr bool is_pointer = std::is_pointer_v; using no_ref_but_pointer = std::tuple>>; - using t2 = std::conditional_t, std::tuple>; + using ret_pointer_or_ret_value = std::conditional_t, std::tuple>; public: inline static constexpr bool have_agrs_value = have_agrs; inline static constexpr bool is_ref_value = is_ref; - using type = std::conditional_t; + inline static constexpr bool is_pointer_value = is_pointer; + using args_pointer_value = std::conditional_t; + using type = std::conditional_t; + + TypeSelector() + { + if constexpr(have_agrs_value) + { + static_assert(std::is_same_v, "if have args then return value must be void"); + } + if constexpr(! have_agrs_value) + { + static_assert(! std::is_same_v, "if have no args then return value can't be void"); + } + static_assert(!is_ref_value, "still have no realization for return type reference"); + static_assert(!is_pointer_value, "still have no realization for return type pointer"); + } }; /** @@ -83,18 +112,20 @@ using namespace msl; */ template struct OwningInvokingStep { - using TFunctionInfo = function_info; - using ret_t = typename TFunctionInfo::ret; - inline static constexpr bool have_agrs = TFunctionInfo::args_count > 0; - using type_selector_t = TypeSelector; - using tuple_t = typename type_selector_t::type; - using qalified_t = typename TFunctionInfo::args; - using class_t = typename TFunctionInfo::cl; + using function_info_t = function_info; + using ret_t = typename function_info_t::ret; + inline static constexpr bool have_agrs = function_info_t::args_count > 0; + using type_selector_t = TypeSelector; + using tuple_t = typename type_selector_t::type; + using qalified_t = typename function_info_t::args; + using class_t = typename function_info_t::cl; // not use dicrectly but in constructor have static assert - const TFunctionInfo function_info_; + const function_info_t function_info_; tuple_t tuple; + // only for call constructor type_selector_t and check static asserts + const type_selector_t ts; /** * @brief The streaming operator which simply deduces type of @@ -113,9 +144,19 @@ using namespace msl; using invoking_t = typename function_info::cl; return OwningInvokingStep{ aFx, std::get(tuple) }; } - if constexpr (!type_selector_t::have_agrs_value && !type_selector_t::is_ref_value) + if constexpr (!type_selector_t::have_agrs_value) { - return OwningInvokingStep{ aFx, std::get<0>(tuple) }; + if constexpr(!type_selector_t::is_ref_value) + { + return OwningInvokingStep{ aFx, std::get<0>(tuple) }; + } + if constexpr(type_selector_t::is_ref_value) + { + // if write staright - static_assert(false, "still no realization when ret val is refernce or pointer"); + // then assert work even if shouldn't + using bool_type_for_assert = typename std::conditional_t; + static_assert(bool_type_for_assert{}, "still no realization when ret val is refernce or pointer"); + } } } @@ -132,7 +173,7 @@ using namespace msl; if constexpr (type_selector_t::have_agrs_value) { static_assert(std::is_same_v, "must be one type"); - this->invokeImpl(std::make_index_sequence{}, aFx, obj); + this->invokeImpl(std::make_index_sequence{}, aFx, obj); } if constexpr (!type_selector_t::have_agrs_value && !type_selector_t::is_ref_value) { diff --git a/test/testMain.cpp b/test/testMain.cpp index a5fd7aa..380f9c5 100644 --- a/test/testMain.cpp +++ b/test/testMain.cpp @@ -63,7 +63,14 @@ struct Object1 i = ii; } - int retGetValue() + int retGetValue() const + { + std::cout << "retGetValue" << std::endl; + ii += 11111; + return ii; + } + + const int& refValue() const { std::cout << "retGetValue" << std::endl; ii += 11111; @@ -129,8 +136,11 @@ constexpr mil::object_invoke invoke { // this case not compile. it is okay because getters C style must accept only refs and pointers //mil::delayedInvoke<&Object3::testFail>("call5") - //mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::retGetValue>("call6"), - mil::delayedInvoke<&Object3::getObject2, &Object2::retObject1, &Object1::retGetValue>("call7") + mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::retGetValue>("call6"), + mil::delayedInvoke<&Object3::getObject2, &Object2::retObject1, &Object1::retGetValue>("call7"), + + // this case not compile, because still have no support for return types pointer and references + // mil::delayedInvoke<&Object3::getObject2, &Object2::retObject1, &Object1::refValue>("call8") }; From a5a240c7e4631bf9aa9ec4c56871415bb045871b Mon Sep 17 00:00:00 2001 From: Alexander Kulikov Date: Sun, 23 Feb 2020 12:03:16 +0300 Subject: [PATCH 05/10] review revision correction step 2; --- include/chain_invoke.h | 26 ++++++++++++++++++++++---- include/function_info.h | 35 ++++++++++++++++++----------------- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/include/chain_invoke.h b/include/chain_invoke.h index 2b4ae00..3b93544 100644 --- a/include/chain_invoke.h +++ b/include/chain_invoke.h @@ -64,8 +64,8 @@ using namespace msl; /** * @brief TypeSelector will select what tuple of agrs will get from function * tuple fow univsality and compatibility - * @tparam have_agrs have function atgs or no - * @tparam TRet return type + * @tparam have_agrs have function args or no + * @tparam TRet return type of function * @tparam stack_args tuple of args if function have_agrs * @details Possible three variants which described below // 1) if have agrs - then return type must be void and function params must @@ -87,6 +87,7 @@ using namespace msl; inline static constexpr bool have_agrs_value = have_agrs; inline static constexpr bool is_ref_value = is_ref; inline static constexpr bool is_pointer_value = is_pointer; + inline static constexpr bool is_copy_value = !have_agrs_value && !is_ref_value && !is_pointer_value; using args_pointer_value = std::conditional_t; using type = std::conditional_t; @@ -144,7 +145,7 @@ using namespace msl; using invoking_t = typename function_info::cl; return OwningInvokingStep{ aFx, std::get(tuple) }; } - if constexpr (!type_selector_t::have_agrs_value) + else { if constexpr(!type_selector_t::is_ref_value) { @@ -157,6 +158,13 @@ using namespace msl; using bool_type_for_assert = typename std::conditional_t; static_assert(bool_type_for_assert{}, "still no realization when ret val is refernce or pointer"); } + if constexpr(type_selector_t::is_pointer_value) + { + // if write staright - static_assert(false, "still no realization when ret val is refernce or pointer"); + // then assert work even if shouldn't + using bool_type_for_assert = typename std::conditional_t; + static_assert(bool_type_for_assert{}, "still no realization when ret val is refernce or pointer"); + } } } @@ -175,11 +183,21 @@ using namespace msl; static_assert(std::is_same_v, "must be one type"); this->invokeImpl(std::make_index_sequence{}, aFx, obj); } - if constexpr (!type_selector_t::have_agrs_value && !type_selector_t::is_ref_value) + else if constexpr (type_selector_t::is_copy_value) { static_assert(std::is_same_v, "must be one type"); this->invokeImplWithret(aFx, obj); } + else if constexpr (type_selector_t::is_ref_value) + { + using bool_type_for_assert = typename std::conditional_t; + static_assert(bool_type_for_assert{}, "still no realization when ret val is refernce"); + } + else if constexpr (type_selector_t::is_pointer_value) + { + using bool_type_for_assert = typename std::conditional_t; + static_assert(bool_type_for_assert{}, "still no realization when ret val is pointer"); + } } private: /** diff --git a/include/function_info.h b/include/function_info.h index 9726602..885261d 100644 --- a/include/function_info.h +++ b/include/function_info.h @@ -26,6 +26,19 @@ #include #include +// this macro will be undefined in the end this file +#ifdef MARCRO_CHECK_THAN_REF_OR_POINTER +#error "MARCRO_CHECK_THAN_REF_OR_POINTER already defined" +#endif +#define MARCRO_CHECK_THAN_REF_OR_POINTER(ClassName)\ + {\ + ClassName()\ + {\ + detail::checkThanRefOrPointer();\ + }\ + }; +// endmacro defrnition + /** * @brief msl component namespace */ @@ -62,19 +75,6 @@ namespace msl { } /* end of namespace detal */ -// this macro will be unded in this file -#ifdef MARCRO_CHECK_THAN_REF_OR_POINTER -#error "MARCRO_CHECK_THAN_REF_OR_POINTER already defined" -#endif -#define MARCRO_CHECK_THAN_REF_OR_POINTER(ClassName)\ - {\ - ClassName()\ - {\ - detail::checkThanRefOrPointer();\ - }\ - }; -// endmacro defrnition - /** * @brief The function info base definition * @@ -417,10 +417,11 @@ MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) : detail::method_function_info MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) -#ifdef MARCRO_CHECK_THAN_REF_OR_POINTER -#undef MARCRO_CHECK_THAN_REF_OR_POINTER -#endif - } /* end of namespace msl */ +#ifndef MARCRO_CHECK_THAN_REF_OR_POINTER +#error "have no macro MARCRO_CHECK_THAN_REF_OR_POINTER" +#endif +#undef MARCRO_CHECK_THAN_REF_OR_POINTER + #endif /* end of #ifndef INCLUDE__FUNCTION_INFO__H */ From 9a476c39ad647a1f8db657c47dec56461776fc7f Mon Sep 17 00:00:00 2001 From: Alexander Kulikov Date: Sun, 23 Feb 2020 13:53:33 +0300 Subject: [PATCH 06/10] work with return types pointers and refs; --- include/chain_invoke.h | 42 +++++++++++++++++++++++++------- test/testMain.cpp | 54 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 82 insertions(+), 14 deletions(-) diff --git a/include/chain_invoke.h b/include/chain_invoke.h index 3b93544..9b021ba 100644 --- a/include/chain_invoke.h +++ b/include/chain_invoke.h @@ -81,7 +81,7 @@ using namespace msl; inline static constexpr bool is_ref = std::is_reference_v; inline static constexpr bool is_pointer = std::is_pointer_v; using no_ref_but_pointer = std::tuple>>; - using ret_pointer_or_ret_value = std::conditional_t, std::tuple>; + using ret_pointer_or_ret_value = std::conditional_t>; public: inline static constexpr bool have_agrs_value = have_agrs; @@ -101,8 +101,6 @@ using namespace msl; { static_assert(! std::is_same_v, "if have no args then return value can't be void"); } - static_assert(!is_ref_value, "still have no realization for return type reference"); - static_assert(!is_pointer_value, "still have no realization for return type pointer"); } }; @@ -151,20 +149,25 @@ using namespace msl; { return OwningInvokingStep{ aFx, std::get<0>(tuple) }; } - if constexpr(type_selector_t::is_ref_value) + else if constexpr(type_selector_t::is_ref_value) { // if write staright - static_assert(false, "still no realization when ret val is refernce or pointer"); // then assert work even if shouldn't using bool_type_for_assert = typename std::conditional_t; static_assert(bool_type_for_assert{}, "still no realization when ret val is refernce or pointer"); } - if constexpr(type_selector_t::is_pointer_value) + else if constexpr(type_selector_t::is_pointer_value) { // if write staright - static_assert(false, "still no realization when ret val is refernce or pointer"); // then assert work even if shouldn't using bool_type_for_assert = typename std::conditional_t; static_assert(bool_type_for_assert{}, "still no realization when ret val is refernce or pointer"); } + else + { + // type_selector_t::have_agrs_value myst be false here + static_assert(type_selector_t::have_agrs_value, "unknown compile time branch"); + } } } @@ -190,13 +193,18 @@ using namespace msl; } else if constexpr (type_selector_t::is_ref_value) { - using bool_type_for_assert = typename std::conditional_t; - static_assert(bool_type_for_assert{}, "still no realization when ret val is refernce"); + static_assert(std::is_same_v, "must be one type"); + this->invokeImplWithRefret(aFx, obj); } else if constexpr (type_selector_t::is_pointer_value) { - using bool_type_for_assert = typename std::conditional_t; - static_assert(bool_type_for_assert{}, "still no realization when ret val is pointer"); + static_assert(std::is_same_v, "must be one type"); + this->invokeImplWithPtrret(aFx, obj); + } + else + { + // type_selector_t::have_agrs_value myst be false here + static_assert(type_selector_t::have_agrs_value, "unknown compile time branch"); } } private: @@ -217,6 +225,22 @@ using namespace msl; static_assert(std::is_same_v, "must be one type"); std::get<0>(tuple) = (obj.*aFx)(); } + + template + constexpr void invokeImplWithRefret(Fx const & aFx, Obj & obj) { + static_assert(std::is_same_v, "must be one type"); + decltype(auto) ret_val = (obj.*aFx)(); + static_assert(std::is_reference_v, "ret value must be reference"); + std::get<0>(tuple) = &ret_val; + } + + template + constexpr void invokeImplWithPtrret(Fx const & aFx, Obj & obj) { + static_assert(std::is_same_v, "must be one type"); + decltype(auto) ret_val = (obj.*aFx)(); + static_assert(std::is_pointer_v, "ret value must be reference"); + std::get<0>(tuple) = ret_val; + } }; /** diff --git a/test/testMain.cpp b/test/testMain.cpp index 380f9c5..18c8ce4 100644 --- a/test/testMain.cpp +++ b/test/testMain.cpp @@ -25,6 +25,11 @@ #include +#ifdef PRINT_DEBUG_INFO +#erro "PRINT_DEBUG_INFO already used" +#endif +//#define PRINT_DEBUG_INFO + template struct InstanceCounter { static size_t instances; @@ -39,16 +44,20 @@ struct InstanceCounter { void incAndLog() const { ++instances; +#ifdef PRINT_DEBUG_INFO std::cout << " +++New object \'" << typeid(T).name() << "\', addr: \'" << static_cast(this) << "\' created, total: \'" << instances << "\'" << std::endl; +#endif } void decAndLog() const { --instances; +#ifdef PRINT_DEBUG_INFO std::cout << " ---Object \'" << typeid(T).name() << "\', addr: \'" << static_cast(this) << "\' destroyed, total: \'" << instances << "\'" << std::endl; +#endif } }; @@ -58,37 +67,56 @@ size_t InstanceCounter::instances { 0ull }; struct Object1 : public InstanceCounter { void getValue(int & i) { - // std::cout << " getValue invoked!" << std::endl; +#ifdef PRINT_DEBUG_INFO + std::cout << " getValue invoked!" << std::endl; +#endif ii += 11111; i = ii; } int retGetValue() const { +#ifdef PRINT_DEBUG_INFO std::cout << "retGetValue" << std::endl; +#endif ii += 11111; return ii; } const int& refValue() const { +#ifdef PRINT_DEBUG_INFO std::cout << "retGetValue" << std::endl; +#endif ii += 11111; return ii; } + const int* ptrValue() const + { +#ifdef PRINT_DEBUG_INFO + std::cout << "retGetValue" << std::endl; +#endif + ii += 11111; + return ⅈ + } + inline static int ii { 11111 }; }; struct Object2 : public InstanceCounter { void getObject1(Object1 & obj) { - // std::cout << " getObject1 invoked!" << std::endl; +#ifdef PRINT_DEBUG_INFO + std::cout << " getObject1 invoked!" << std::endl; +#endif obj = obj_; } Object1 retObject1() const { +#ifdef PRINT_DEBUG_INFO std::cout << " retObject1 invoked" << std::endl; +#endif return obj_; } @@ -98,7 +126,9 @@ struct Object2 struct Object3 : public InstanceCounter { void getObject2(Object2 * obj) { - //std::cout << " getObject2 invoked!" << std::endl; +#ifdef PRINT_DEBUG_INFO + std::cout << " getObject2 invoked!" << std::endl; +#endif *obj = obj_; } @@ -119,9 +149,22 @@ struct Serializer { std::cout << "\'\n"; } + template + static auto& get_wrapper(const T& val) + { + constexpr bool is_ponter = std::is_pointer_v>; + if constexpr(is_ponter) { + return *val; + } else { + return val; + } + } + template static std::ostream & putStream(std::ostream & aOs, Tuple const & t, std::index_sequence) { - return (aOs << ... << std::get(t)); + (aOs << ... << get_wrapper(std::get(t))); + + return aOs; } }; @@ -140,7 +183,8 @@ constexpr mil::object_invoke invoke { mil::delayedInvoke<&Object3::getObject2, &Object2::retObject1, &Object1::retGetValue>("call7"), // this case not compile, because still have no support for return types pointer and references - // mil::delayedInvoke<&Object3::getObject2, &Object2::retObject1, &Object1::refValue>("call8") + mil::delayedInvoke<&Object3::getObject2, &Object2::retObject1, &Object1::refValue>("call8"), + mil::delayedInvoke<&Object3::getObject2, &Object2::retObject1, &Object1::ptrValue>("call9") }; From 8a0941f2e0d85ff61a9749bcf5039b4ebba7da4b Mon Sep 17 00:00:00 2001 From: Alexander Kulikov Date: Sun, 23 Feb 2020 19:38:49 +0300 Subject: [PATCH 07/10] deleted useless code and add simple example; --- include/object_invoke.h | 22 ++-------------------- test/testMain.cpp | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/include/object_invoke.h b/include/object_invoke.h index ca5cbb6..e1b8074 100644 --- a/include/object_invoke.h +++ b/include/object_invoke.h @@ -159,24 +159,6 @@ namespace detail { }; } /* end of namespace detail */ - /** - * @brief Supporting struct, which holds the acceptor type - * - * @tparam TAcceptor Type of the acceptor - */ - template - struct acceptor {}; - - /** - * @brief Make the acceptor basing on the provided - * - * @tparam TAcceptor Type to use as acceptor - */ - template - constexpr inline auto useAcceptor() { - return acceptor { }; - } - /** * @brief Creates the delayed invoke (used to pass method list into the * object_invoke) @@ -217,7 +199,7 @@ namespace detail { * @tparam TInvokers Types if the invokers */ template - explicit constexpr object_invoke(acceptor, TInvokers && ... aInvokers) + explicit constexpr object_invoke(acceptor_t, TInvokers && ... aInvokers) : m_delayed_invokers { aInvokers.template getDelayedInvoke()... } {} @@ -236,7 +218,7 @@ namespace detail { /* class deduction guides */ template - explicit object_invoke(acceptor, T ...) -> object_invoke::cl, sizeof...(T), TResultAcceptor>; + explicit object_invoke(TResultAcceptor, T ...) -> object_invoke::cl, sizeof...(T), TResultAcceptor>; } /* end of namespace mil */ diff --git a/test/testMain.cpp b/test/testMain.cpp index 18c8ce4..a9dafcc 100644 --- a/test/testMain.cpp +++ b/test/testMain.cpp @@ -120,6 +120,13 @@ struct Object2 return obj_; } + const Object1& refObject1() const { +#ifdef PRINT_DEBUG_INFO + std::cout << " refObject1 invoked" << std::endl; +#endif + return obj_; + } + Object1 obj_; }; @@ -170,7 +177,7 @@ struct Serializer { constexpr mil::object_invoke invoke { - mil::useAcceptor(), + Serializer{}, mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("call1"), mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("call2"), mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("call3"), @@ -190,6 +197,16 @@ constexpr mil::object_invoke invoke { int main() { Object3 obj {}; + + { + Serializer acceptor; + + const auto invoke_forwarder = mil::delayedInvoke<&Object3::getObject2, &Object2::retObject1, &Object1::ptrValue>("separate_test"); + const auto delayed_invoker = invoke_forwarder.template getDelayedInvoke(); + + delayed_invoker(obj, acceptor); + } + Serializer si; //invoke.set_logger(std::function{[](const std::string& v){ std::cout << v << std::endl; }}); From cddd310779381d4fb4160bcb6266a03ff87aedb2 Mon Sep 17 00:00:00 2001 From: Alexander Kulikov Date: Sun, 23 Feb 2020 21:30:25 +0300 Subject: [PATCH 08/10] now work almost in any combination. Need more good tests; --- include/chain_invoke.h | 31 +++++++++------ include/object_invoke.h | 3 ++ test/testMain.cpp | 84 +++++++++++++++++++++++++---------------- 3 files changed, 73 insertions(+), 45 deletions(-) diff --git a/include/chain_invoke.h b/include/chain_invoke.h index 9b021ba..f0a0dd3 100644 --- a/include/chain_invoke.h +++ b/include/chain_invoke.h @@ -28,6 +28,7 @@ /* STL */ #include #include +#include #include /** @@ -145,19 +146,19 @@ using namespace msl; } else { - if constexpr(!type_selector_t::is_ref_value) + if constexpr(type_selector_t::is_copy_value) { + static_assert(std::tuple_size_v == 1, "tuple size must be 1"); return OwningInvokingStep{ aFx, std::get<0>(tuple) }; } else if constexpr(type_selector_t::is_ref_value) { - // if write staright - static_assert(false, "still no realization when ret val is refernce or pointer"); - // then assert work even if shouldn't - using bool_type_for_assert = typename std::conditional_t; - static_assert(bool_type_for_assert{}, "still no realization when ret val is refernce or pointer"); + static_assert(std::tuple_size_v == 1, "tuple size must be 1"); + return OwningInvokingStep{ aFx, std::get<0>(tuple) }; } else if constexpr(type_selector_t::is_pointer_value) { + static_assert(std::tuple_size_v == 1, "tuple size must be 1"); // if write staright - static_assert(false, "still no realization when ret val is refernce or pointer"); // then assert work even if shouldn't using bool_type_for_assert = typename std::conditional_t; @@ -193,12 +194,14 @@ using namespace msl; } else if constexpr (type_selector_t::is_ref_value) { - static_assert(std::is_same_v, "must be one type"); + using compare_obj_t = std::remove_const_t>; + static_assert(std::is_same_v, compare_obj_t>, "must be one type"); this->invokeImplWithRefret(aFx, obj); } else if constexpr (type_selector_t::is_pointer_value) { - static_assert(std::is_same_v, "must be one type"); + using compare_obj_t = std::remove_const_t>; + static_assert(std::is_same_v, compare_obj_t>, "must be one type"); this->invokeImplWithPtrret(aFx, obj); } else @@ -228,17 +231,21 @@ using namespace msl; template constexpr void invokeImplWithRefret(Fx const & aFx, Obj & obj) { - static_assert(std::is_same_v, "must be one type"); - decltype(auto) ret_val = (obj.*aFx)(); + using compare_obj_t = std::remove_const_t>; + static_assert(std::is_same_v, compare_obj_t>, "must be one type"); + decltype(auto) ret_val = std::invoke(aFx, obj); static_assert(std::is_reference_v, "ret value must be reference"); std::get<0>(tuple) = &ret_val; } template constexpr void invokeImplWithPtrret(Fx const & aFx, Obj & obj) { - static_assert(std::is_same_v, "must be one type"); - decltype(auto) ret_val = (obj.*aFx)(); - static_assert(std::is_pointer_v, "ret value must be reference"); + // sometimes object can be ref to pointer + using compare_obj_t = std::remove_const_t>; + static_assert(std::is_same_v, compare_obj_t>, "must be one type"); + + decltype(auto) ret_val = std::invoke(aFx, obj); + static_assert(std::is_pointer_v, "ret value must be pointer"); std::get<0>(tuple) = ret_val; } }; diff --git a/include/object_invoke.h b/include/object_invoke.h index e1b8074..ad55668 100644 --- a/include/object_invoke.h +++ b/include/object_invoke.h @@ -81,6 +81,9 @@ namespace detail { constexpr void operator()(object_t & aObject, acceptor_t & aAcceptor) const { (*m_invokerPtr)(aObject, m_tag, aAcceptor); } + constexpr void operator()(object_t* aObject, acceptor_t & aAcceptor) const { + (*m_invokerPtr)(*aObject, m_tag, aAcceptor); + } private: /** * @brief The private invoker, performs chain invoke for the diff --git a/test/testMain.cpp b/test/testMain.cpp index a9dafcc..de5da3a 100644 --- a/test/testMain.cpp +++ b/test/testMain.cpp @@ -66,63 +66,63 @@ size_t InstanceCounter::instances { 0ull }; struct Object1 : public InstanceCounter { - void getValue(int & i) { + void CStyleGetValue(int & i) { #ifdef PRINT_DEBUG_INFO - std::cout << " getValue invoked!" << std::endl; + std::cout << __FUNCTION__ << " invoked!" << std::endl; #endif - ii += 11111; + ii += 1; i = ii; } - int retGetValue() const + int getValue() const { #ifdef PRINT_DEBUG_INFO - std::cout << "retGetValue" << std::endl; + std::cout << __FUNCTION__ << std::endl; #endif - ii += 11111; + ii += 1; return ii; } const int& refValue() const { #ifdef PRINT_DEBUG_INFO - std::cout << "retGetValue" << std::endl; + std::cout << __FUNCTION__ << std::endl; #endif - ii += 11111; + ii += 1; return ii; } const int* ptrValue() const { #ifdef PRINT_DEBUG_INFO - std::cout << "retGetValue" << std::endl; + std::cout << __FUNCTION__ << std::endl; #endif - ii += 11111; + ii += 1; return ⅈ } - inline static int ii { 11111 }; + inline static int ii { 0 }; }; struct Object2 : public InstanceCounter { - void getObject1(Object1 & obj) { + void CStyleGetObject1(Object1 & obj) { #ifdef PRINT_DEBUG_INFO - std::cout << " getObject1 invoked!" << std::endl; + std::cout << __FUNCTION__ << " invoked!" << std::endl; #endif obj = obj_; } Object1 retObject1() const { #ifdef PRINT_DEBUG_INFO - std::cout << " retObject1 invoked" << std::endl; + std::cout << __FUNCTION__ << " invoked" << std::endl; #endif return obj_; } const Object1& refObject1() const { #ifdef PRINT_DEBUG_INFO - std::cout << " refObject1 invoked" << std::endl; + std::cout << __FUNCTION__ << " invoked" << std::endl; #endif return obj_; } @@ -132,13 +132,27 @@ struct Object2 struct Object3 : public InstanceCounter { - void getObject2(Object2 * obj) { + void CStyleGetObject2(Object2 * obj) { #ifdef PRINT_DEBUG_INFO - std::cout << " getObject2 invoked!" << std::endl; + std::cout << __FUNCTION__ << " invoked!" << std::endl; #endif *obj = obj_; } + const Object2& refObject2() { +#ifdef PRINT_DEBUG_INFO + std::cout << __FUNCTION__ << " invoked!" << std::endl; +#endif + return obj_; + } + + const Object2* ptrObject2() { +#ifdef PRINT_DEBUG_INFO + std::cout << __FUNCTION__ << " invoked!" << std::endl; +#endif + return &obj_; + } + void testFail(int c) { c = 15; @@ -178,38 +192,42 @@ struct Serializer { constexpr mil::object_invoke invoke { Serializer{}, - mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("call1"), - mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("call2"), - mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("call3"), - mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("call4"), + mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::CStyleGetObject1, &Object1::CStyleGetValue>("call1"), + mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::CStyleGetObject1, &Object1::CStyleGetValue>("call2"), + mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::CStyleGetObject1, &Object1::CStyleGetValue>("call3"), + mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::CStyleGetObject1, &Object1::CStyleGetValue>("call4"), // this case not compile. it is okay because getters C style must accept only refs and pointers //mil::delayedInvoke<&Object3::testFail>("call5") - mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::retGetValue>("call6"), - mil::delayedInvoke<&Object3::getObject2, &Object2::retObject1, &Object1::retGetValue>("call7"), + mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::CStyleGetObject1, &Object1::getValue>("call6"), + mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::retObject1, &Object1::getValue>("call7"), + + mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::retObject1, &Object1::refValue>("call8"), + mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::retObject1, &Object1::ptrValue>("call9"), + mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::refObject1, &Object1::ptrValue>("call9"), - // this case not compile, because still have no support for return types pointer and references - mil::delayedInvoke<&Object3::getObject2, &Object2::retObject1, &Object1::refValue>("call8"), - mil::delayedInvoke<&Object3::getObject2, &Object2::retObject1, &Object1::ptrValue>("call9") + mil::delayedInvoke<&Object3::refObject2, &Object2::refObject1, &Object1::ptrValue>("call9") }; int main() { - Object3 obj {}; + Object3 obj; + Serializer si; { - Serializer acceptor; - - const auto invoke_forwarder = mil::delayedInvoke<&Object3::getObject2, &Object2::retObject1, &Object1::ptrValue>("separate_test"); + const auto invoke_forwarder = mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::retObject1, &Object1::ptrValue>("separate_test_1"); const auto delayed_invoker = invoke_forwarder.template getDelayedInvoke(); - delayed_invoker(obj, acceptor); + delayed_invoker(obj, si); } + { + const auto invoke_forwarder = mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::refObject1, &Object1::ptrValue>("separate_test_2"); + const auto delayed_invoker = invoke_forwarder.template getDelayedInvoke(); - Serializer si; + delayed_invoker(obj, si); + } - //invoke.set_logger(std::function{[](const std::string& v){ std::cout << v << std::endl; }}); invoke(obj, si); return 0; From 0405dfd1289512c65838ed07a186f5ecb9a7ee2c Mon Sep 17 00:00:00 2001 From: Alexander Kulikov Date: Mon, 24 Feb 2020 00:10:26 +0300 Subject: [PATCH 09/10] bug fix and test coverage. Need better error messages; --- include/chain_invoke.h | 32 ++++++++++---- test/testMain.cpp | 98 +++++++++++++++++++++++++++++------------- 2 files changed, 90 insertions(+), 40 deletions(-) diff --git a/include/chain_invoke.h b/include/chain_invoke.h index f0a0dd3..86f4dd7 100644 --- a/include/chain_invoke.h +++ b/include/chain_invoke.h @@ -159,10 +159,7 @@ using namespace msl; else if constexpr(type_selector_t::is_pointer_value) { static_assert(std::tuple_size_v == 1, "tuple size must be 1"); - // if write staright - static_assert(false, "still no realization when ret val is refernce or pointer"); - // then assert work even if shouldn't - using bool_type_for_assert = typename std::conditional_t; - static_assert(bool_type_for_assert{}, "still no realization when ret val is refernce or pointer"); + return OwningInvokingStep{ aFx, std::get<0>(tuple) }; } else { @@ -184,24 +181,30 @@ using namespace msl; { if constexpr (type_selector_t::have_agrs_value) { - static_assert(std::is_same_v, "must be one type"); + using compare_obj_t = std::remove_const_t>; + static_assert(std::is_same_v, compare_obj_t>, "must be one type"); + this->invokeImpl(std::make_index_sequence{}, aFx, obj); } else if constexpr (type_selector_t::is_copy_value) { - static_assert(std::is_same_v, "must be one type"); + using compare_obj_t = std::remove_const_t>; + static_assert(std::is_same_v, compare_obj_t>, "must be one type"); + this->invokeImplWithret(aFx, obj); } else if constexpr (type_selector_t::is_ref_value) { using compare_obj_t = std::remove_const_t>; static_assert(std::is_same_v, compare_obj_t>, "must be one type"); + this->invokeImplWithRefret(aFx, obj); } else if constexpr (type_selector_t::is_pointer_value) { using compare_obj_t = std::remove_const_t>; static_assert(std::is_same_v, compare_obj_t>, "must be one type"); + this->invokeImplWithPtrret(aFx, obj); } else @@ -219,14 +222,25 @@ using namespace msl; */ template constexpr void invokeImpl(std::index_sequence, Fx const & aFx, Obj & obj) { - static_assert(std::is_same_v, "must be one type"); + using compare_obj_t = std::remove_const_t>; + static_assert(std::is_same_v, compare_obj_t>, "must be one type"); + (obj.*aFx)(conditionalAddressOf>(std::get(tuple))...); } + template + constexpr void invokeImpl(std::index_sequence, Fx const & aFx, Obj* obj) { + using compare_obj_t = std::remove_const_t>; + static_assert(std::is_same_v, compare_obj_t>, "must be one type"); + + (obj->*aFx)(conditionalAddressOf>(std::get(tuple))...); + } template constexpr void invokeImplWithret(Fx const & aFx, Obj & obj) { - static_assert(std::is_same_v, "must be one type"); - std::get<0>(tuple) = (obj.*aFx)(); + using compare_obj_t = std::remove_const_t>; + static_assert(std::is_same_v, compare_obj_t>, "must be one type"); + + std::get<0>(tuple) = std::invoke(aFx, obj); } template diff --git a/test/testMain.cpp b/test/testMain.cpp index de5da3a..70b58bc 100644 --- a/test/testMain.cpp +++ b/test/testMain.cpp @@ -66,7 +66,7 @@ size_t InstanceCounter::instances { 0ull }; struct Object1 : public InstanceCounter { - void CStyleGetValue(int & i) { + void CStyleGetValue(int & i) const { #ifdef PRINT_DEBUG_INFO std::cout << __FUNCTION__ << " invoked!" << std::endl; #endif @@ -106,14 +106,14 @@ struct Object1 struct Object2 : public InstanceCounter { - void CStyleGetObject1(Object1 & obj) { + void CStyleGetObject1(Object1 & obj) const { #ifdef PRINT_DEBUG_INFO std::cout << __FUNCTION__ << " invoked!" << std::endl; #endif obj = obj_; } - Object1 retObject1() const { + Object1 getObject1() const { #ifdef PRINT_DEBUG_INFO std::cout << __FUNCTION__ << " invoked" << std::endl; #endif @@ -127,18 +127,32 @@ struct Object2 return obj_; } + const Object1& ptrObject1() const { +#ifdef PRINT_DEBUG_INFO + std::cout << __FUNCTION__ << " invoked" << std::endl; +#endif + return obj_; + } + Object1 obj_; }; struct Object3 : public InstanceCounter { - void CStyleGetObject2(Object2 * obj) { + void CStyleGetObject2(Object2 * obj) const { #ifdef PRINT_DEBUG_INFO std::cout << __FUNCTION__ << " invoked!" << std::endl; #endif *obj = obj_; } + Object2 getObject2() const { +#ifdef PRINT_DEBUG_INFO + std::cout << __FUNCTION__ << " invoked!" << std::endl; +#endif + return obj_; + } + const Object2& refObject2() { #ifdef PRINT_DEBUG_INFO std::cout << __FUNCTION__ << " invoked!" << std::endl; @@ -189,46 +203,68 @@ struct Serializer { } }; +template +struct value { + constexpr inline static auto F = val; +}; -constexpr mil::object_invoke invoke { - Serializer{}, - mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::CStyleGetObject1, &Object1::CStyleGetValue>("call1"), - mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::CStyleGetObject1, &Object1::CStyleGetValue>("call2"), - mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::CStyleGetObject1, &Object1::CStyleGetValue>("call3"), - mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::CStyleGetObject1, &Object1::CStyleGetValue>("call4"), - - // this case not compile. it is okay because getters C style must accept only refs and pointers - //mil::delayedInvoke<&Object3::testFail>("call5") - - mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::CStyleGetObject1, &Object1::getValue>("call6"), - mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::retObject1, &Object1::getValue>("call7"), - - mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::retObject1, &Object1::refValue>("call8"), - mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::retObject1, &Object1::ptrValue>("call9"), - mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::refObject1, &Object1::ptrValue>("call9"), +template +using values_tuple = std::tuple...>; - mil::delayedInvoke<&Object3::refObject2, &Object2::refObject1, &Object1::ptrValue>("call9") -}; +using obj3_methods_t = values_tuple<&Object3::CStyleGetObject2, &Object3::getObject2, &Object3::refObject2, &Object3::ptrObject2>; +using obj2_methods_t = values_tuple<&Object2::CStyleGetObject1, &Object2::getObject1, &Object2::refObject1, &Object2::ptrObject1>; +using obj1_methods_t = values_tuple<&Object1::CStyleGetValue, &Object1::getValue, &Object1::refValue, &Object1::ptrValue>; +template +void constexpr one_test(Object3& obj, Serializer& si) +{ + constexpr mil::object_invoke invoke { + Serializer{}, + mil::delayedInvoke("tag1") + }; -int main() { - Object3 obj; - Serializer si; + invoke(obj, si); { - const auto invoke_forwarder = mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::retObject1, &Object1::ptrValue>("separate_test_1"); + const auto invoke_forwarder = mil::delayedInvoke("tag2"); const auto delayed_invoker = invoke_forwarder.template getDelayedInvoke(); delayed_invoker(obj, si); } - { - const auto invoke_forwarder = mil::delayedInvoke<&Object3::CStyleGetObject2, &Object2::refObject1, &Object1::ptrValue>("separate_test_2"); - const auto delayed_invoker = invoke_forwarder.template getDelayedInvoke(); +} - delayed_invoker(obj, si); +template +void constexpr cross_test(Object3& obj, Serializer& si, + const obj3_methods_t& obj3_methods, const obj2_methods_t& obj2_methods, const obj1_methods_t& obj1_methods) +{ + one_test(obj3_methods).F, std::get(obj2_methods).F, std::get(obj1_methods).F>(obj, si); + if constexpr(NObj2 != 0) { + cross_test(obj, si, obj3_methods, obj2_methods, obj1_methods); + + if constexpr(NObj1 != 0) { + cross_test(obj, si, obj3_methods, obj2_methods, obj1_methods); + } + } +} + +template +void constexpr block_test() +{ + Object3 obj; + Serializer si; + + const obj3_methods_t obj3_methods{}; + const obj2_methods_t obj2_methods{}; + const obj1_methods_t obj1_methods{}; + + cross_test(obj, si, obj3_methods, obj2_methods, obj1_methods); + if constexpr (N != 0) { + cross_test(obj, si, obj3_methods, obj2_methods, obj1_methods); } +} - invoke(obj, si); +int main() { + block_test<3>(); return 0; } From afe34683d7ce88646aa0ce338f65a834f1c00947 Mon Sep 17 00:00:00 2001 From: Alexander Kulikov Date: Mon, 24 Feb 2020 10:59:09 +0300 Subject: [PATCH 10/10] after review fix; --- include/chain_invoke.h | 21 ++++++++++++++++++++- test/testMain.cpp | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/chain_invoke.h b/include/chain_invoke.h index 86f4dd7..56fb1e0 100644 --- a/include/chain_invoke.h +++ b/include/chain_invoke.h @@ -222,7 +222,7 @@ using namespace msl; */ template constexpr void invokeImpl(std::index_sequence, Fx const & aFx, Obj & obj) { - using compare_obj_t = std::remove_const_t>; + using compare_obj_t = std::remove_const_t; static_assert(std::is_same_v, compare_obj_t>, "must be one type"); (obj.*aFx)(conditionalAddressOf>(std::get(tuple))...); @@ -231,6 +231,9 @@ using namespace msl; constexpr void invokeImpl(std::index_sequence, Fx const & aFx, Obj* obj) { using compare_obj_t = std::remove_const_t>; static_assert(std::is_same_v, compare_obj_t>, "must be one type"); + if(obj == nullptr) { + throw std::runtime_error(std::string{"object nullptr at "} + __FUNCTION__); + } (obj->*aFx)(conditionalAddressOf>(std::get(tuple))...); } @@ -239,6 +242,11 @@ using namespace msl; constexpr void invokeImplWithret(Fx const & aFx, Obj & obj) { using compare_obj_t = std::remove_const_t>; static_assert(std::is_same_v, compare_obj_t>, "must be one type"); + if constexpr(std::is_pointer_v){ + if(obj == nullptr) { + throw std::runtime_error(std::string{"object nullptr at "} + __FUNCTION__); + } + } std::get<0>(tuple) = std::invoke(aFx, obj); } @@ -247,6 +255,12 @@ using namespace msl; constexpr void invokeImplWithRefret(Fx const & aFx, Obj & obj) { using compare_obj_t = std::remove_const_t>; static_assert(std::is_same_v, compare_obj_t>, "must be one type"); + if constexpr(std::is_pointer_v){ + if(obj == nullptr) { + throw std::runtime_error(std::string{"object nullptr at "} + __FUNCTION__); + } + } + decltype(auto) ret_val = std::invoke(aFx, obj); static_assert(std::is_reference_v, "ret value must be reference"); std::get<0>(tuple) = &ret_val; @@ -257,6 +271,11 @@ using namespace msl; // sometimes object can be ref to pointer using compare_obj_t = std::remove_const_t>; static_assert(std::is_same_v, compare_obj_t>, "must be one type"); + if constexpr(std::is_pointer_v){ + if(obj == nullptr) { + throw std::runtime_error(std::string{"object nullptr at "} + __FUNCTION__); + } + } decltype(auto) ret_val = std::invoke(aFx, obj); static_assert(std::is_pointer_v, "ret value must be pointer"); diff --git a/test/testMain.cpp b/test/testMain.cpp index 70b58bc..4841845 100644 --- a/test/testMain.cpp +++ b/test/testMain.cpp @@ -26,7 +26,7 @@ #include #ifdef PRINT_DEBUG_INFO -#erro "PRINT_DEBUG_INFO already used" +#error "PRINT_DEBUG_INFO already used" #endif //#define PRINT_DEBUG_INFO