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..9b021ba 100644 --- a/include/chain_invoke.h +++ b/include/chain_invoke.h @@ -61,20 +61,70 @@ 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 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 + // 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 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 ret_pointer_or_ret_value = std::conditional_t>; + + public: + 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; + + 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"); + } + } + }; + /** * @brief The invoking step object, which also holds the tuple * * @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 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; - static constexpr size_t TUPLE_SIZE { std::tuple_size_v }; + // not use dicrectly but in constructor have static assert + 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 @@ -88,8 +138,37 @@ 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) }; + } + else + { + if constexpr(!type_selector_t::is_ref_value) + { + 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"); + } + 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"); + } + } } /** @@ -102,7 +181,31 @@ 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); + } + 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) + { + static_assert(std::is_same_v, "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"); + 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: /** @@ -113,8 +216,31 @@ 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)(); + } + + 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; + } }; /** @@ -146,7 +272,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/include/function_info.h b/include/function_info.h index 424bde4..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 */ @@ -46,6 +59,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 @@ -53,6 +67,12 @@ namespace msl { >; }; + template + void checkThanRefOrPointer() + { + static_assert(((std::is_reference_v || std::is_pointer_v) && ...), "must be pointer or reference"); + } + } /* end of namespace detal */ /** @@ -73,7 +93,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 +107,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 +121,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 +134,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 +148,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 +162,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 +176,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 +190,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 +204,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 +218,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 +232,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 +246,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 +260,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 +274,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 +288,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 +302,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 +316,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 +330,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 +344,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 +358,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 +372,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 +386,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 +400,8 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) /** @@ -372,8 +414,14 @@ namespace msl { */ template struct function_info - : detail::method_function_info {}; + : detail::method_function_info +MARCRO_CHECK_THAN_REF_OR_POINTER(function_info) } /* 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 */ diff --git a/include/object_invoke.h b/include/object_invoke.h index ea831c3..ca5cbb6 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 @@ -96,20 +100,14 @@ namespace mil { /** * @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; }; - - /** - * @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 5925cdb..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,26 +67,78 @@ size_t InstanceCounter::instances { 0ull }; struct Object1 : public InstanceCounter { void getValue(int & i) { - // std::cout << " getValue invoked!" << std::endl; - static int ii { 11111 }; +#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; - (void)obj; +#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_; } + + Object1 obj_; }; 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_; + } + + void testFail(int c) + { + c = 15; + std::cout << c << std::endl; } + + Object2 obj_; }; struct Serializer { @@ -88,20 +149,42 @@ 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; } }; - -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") + mil::delayedInvoke<&Object3::getObject2, &Object2::getObject1, &Object1::getValue>("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"), + + // 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") }; @@ -109,6 +192,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;