diff --git a/headers/meta.hpp/meta_all.hpp b/headers/meta.hpp/meta_all.hpp index cf67b10..5fca320 100644 --- a/headers/meta.hpp/meta_all.hpp +++ b/headers/meta.hpp/meta_all.hpp @@ -54,3 +54,4 @@ #include "meta_utilities/arg.hpp" #include "meta_utilities/inst.hpp" #include "meta_utilities/value.hpp" +#include "meta_utilities/vinvoke.hpp" diff --git a/headers/meta.hpp/meta_states.hpp b/headers/meta.hpp/meta_states.hpp index ff4daea..8af4685 100644 --- a/headers/meta.hpp/meta_states.hpp +++ b/headers/meta.hpp/meta_states.hpp @@ -260,8 +260,8 @@ namespace meta_hpp namespace meta_hpp::detail { struct ctor_state final { - using invoke_impl = std::function)>; - using is_invocable_with_impl = std::function)>; + using invoke_impl = std::function)>; + using is_invocable_with_impl = std::function)>; const ctor_index index; const invoke_impl invoke; @@ -287,8 +287,8 @@ namespace meta_hpp::detail }; struct function_state final { - using invoke_impl = std::function(std::span)>; - using is_invocable_with_impl = std::function)>; + using invoke_impl = std::function(std::span)>; + using is_invocable_with_impl = std::function)>; const function_index index; const invoke_impl invoke; @@ -322,8 +322,8 @@ namespace meta_hpp::detail }; struct method_state final { - using invoke_impl = std::function(const inst&, std::span)>; - using is_invocable_with_impl = std::function)>; + using invoke_impl = std::function(const inst&, std::span)>; + using is_invocable_with_impl = std::function)>; const method_index index; const invoke_impl invoke; diff --git a/headers/meta.hpp/meta_states/ctor.hpp b/headers/meta.hpp/meta_states/ctor.hpp index e501499..203695c 100644 --- a/headers/meta.hpp/meta_states/ctor.hpp +++ b/headers/meta.hpp/meta_states/ctor.hpp @@ -14,7 +14,7 @@ namespace meta_hpp::detail { template < class_kind Class, typename... Args > - value raw_ctor_invoke(std::span args) { + value vargs_invoke(std::span args) { using ct = ctor_traits; using class_type = typename ct::class_type; using argument_types = typename ct::argument_types; @@ -35,7 +35,7 @@ namespace meta_hpp::detail } template < class_kind Class, typename... Args > - bool raw_ctor_is_invocable_with(std::span args) { + bool vargs_is_invocable_with(std::span args) { using ct = ctor_traits; using argument_types = typename ct::argument_types; @@ -55,13 +55,13 @@ namespace meta_hpp::detail template < class_kind Class, typename... Args > ctor_state::invoke_impl make_ctor_invoke() { using namespace std::placeholders; - return std::bind(&raw_ctor_invoke, _1); + return std::bind(&vargs_invoke, _1); } template < class_kind Class, typename... Args > ctor_state::is_invocable_with_impl make_ctor_is_invocable_with() { using namespace std::placeholders; - return std::bind(&raw_ctor_is_invocable_with, _1); + return std::bind(&vargs_is_invocable_with, _1); } } @@ -104,9 +104,9 @@ namespace meta_hpp template < typename... Args > value ctor::invoke(Args&&... args) const { - using namespace detail; if constexpr ( sizeof...(Args) > 0 ) { - std::array vargs{arg{std::forward(args)}...}; + using namespace detail; + const std::array vargs{arg{std::forward(args)}...}; return state_->invoke(vargs); } else { return state_->invoke({}); @@ -120,9 +120,9 @@ namespace meta_hpp template < typename... Args > bool ctor::is_invocable_with() const noexcept { - using namespace detail; if constexpr ( sizeof...(Args) > 0 ) { - std::array vargs{arg_base{type_list{}}...}; + using namespace detail; + const std::array vargs{arg_base{type_list{}}...}; return state_->is_invocable_with(vargs); } else { return state_->is_invocable_with({}); @@ -131,9 +131,9 @@ namespace meta_hpp template < typename... Args > bool ctor::is_invocable_with(Args&&... args) const noexcept { - using namespace detail; if constexpr ( sizeof...(Args) > 0 ) { - std::array vargs{arg{std::forward(args)}...}; + using namespace detail; + const std::array vargs{arg_base{std::forward(args)}...}; return state_->is_invocable_with(vargs); } else { return state_->is_invocable_with({}); diff --git a/headers/meta.hpp/meta_states/function.hpp b/headers/meta.hpp/meta_states/function.hpp index f1efd24..02447a8 100644 --- a/headers/meta.hpp/meta_states/function.hpp +++ b/headers/meta.hpp/meta_states/function.hpp @@ -14,7 +14,7 @@ namespace meta_hpp::detail { template < function_kind Function > - std::optional raw_function_invoke(Function function, std::span args) { + std::optional vargs_invoke(Function function, std::span args) { using ft = function_traits; using return_type = typename ft::return_type; using argument_types = typename ft::argument_types; @@ -24,7 +24,7 @@ namespace meta_hpp::detail } // NOLINTNEXTLINE(readability-named-parameter) - return std::invoke([&function, &args](std::index_sequence){ + return std::invoke([function = std::move(function), &args](std::index_sequence){ if ( !(... && (args.data() + Is)->can_cast_to>()) ) { throw std::logic_error("an attempt to call a function with incorrect argument types"); } @@ -44,7 +44,7 @@ namespace meta_hpp::detail } template < function_kind Function > - bool raw_function_is_invocable_with(std::span args) { + bool vargs_is_invocable_with(std::span args) { using ft = function_traits; using argument_types = typename ft::argument_types; @@ -64,13 +64,13 @@ namespace meta_hpp::detail template < function_kind Function > function_state::invoke_impl make_function_invoke(Function function) { using namespace std::placeholders; - return std::bind(&raw_function_invoke, function, _1); + return std::bind(&vargs_invoke, std::move(function), _1); } template < function_kind Function > function_state::is_invocable_with_impl make_function_is_invocable_with() { using namespace std::placeholders; - return std::bind(&raw_function_is_invocable_with, _1); + return std::bind(&vargs_is_invocable_with, _1); } } @@ -79,7 +79,7 @@ namespace meta_hpp::detail template < function_kind Function > function_state::function_state(function_index index, Function function) : index{std::move(index)} - , invoke{make_function_invoke(function)} + , invoke{make_function_invoke(std::move(function))} , is_invocable_with{make_function_is_invocable_with()} {} template < function_kind Function > @@ -116,9 +116,9 @@ namespace meta_hpp template < typename... Args > std::optional function::invoke(Args&&... args) const { - using namespace detail; if constexpr ( sizeof...(Args) > 0 ) { - std::array vargs{arg{std::forward(args)}...}; + using namespace detail; + const std::array vargs{arg{std::forward(args)}...}; return state_->invoke(vargs); } else { return state_->invoke({}); @@ -132,9 +132,9 @@ namespace meta_hpp template < typename... Args > bool function::is_invocable_with() const noexcept { - using namespace detail; if constexpr ( sizeof...(Args) > 0 ) { - std::array vargs{arg_base{type_list{}}...}; + using namespace detail; + const std::array vargs{arg_base{type_list{}}...}; return state_->is_invocable_with(vargs); } else { return state_->is_invocable_with({}); @@ -143,9 +143,9 @@ namespace meta_hpp template < typename... Args > bool function::is_invocable_with(Args&&... args) const noexcept { - using namespace detail; if constexpr ( sizeof...(Args) > 0 ) { - std::array vargs{arg{std::forward(args)}...}; + using namespace detail; + const std::array vargs{arg_base{std::forward(args)}...}; return state_->is_invocable_with(vargs); } else { return state_->is_invocable_with({}); diff --git a/headers/meta.hpp/meta_states/member.hpp b/headers/meta.hpp/meta_states/member.hpp index 6a66ec1..73243b3 100644 --- a/headers/meta.hpp/meta_states/member.hpp +++ b/headers/meta.hpp/meta_states/member.hpp @@ -14,7 +14,7 @@ namespace meta_hpp::detail { template < member_kind Member > - value raw_member_getter(Member member, const inst& inst) { + value vargs_invoke(Member member, const inst& inst) { using mt = member_traits; using class_type = typename mt::class_type; using value_type = typename mt::value_type; @@ -25,10 +25,23 @@ namespace meta_hpp::detail throw std::logic_error("an attempt to get a member with an incorrect instance type"); } - value_type return_value{std::invoke(member, inst.cast())}; + value_type return_value{std::invoke(std::move(member), inst.cast())}; return value{std::forward(return_value)}; } + template < member_kind Member > + bool vargs_is_invocable_with(const inst_base& inst) { + using mt = member_traits; + using class_type = typename mt::class_type; + + using qualified_type = const class_type; + + return inst.can_cast_to(); + } +} + +namespace meta_hpp::detail +{ template < member_kind Member > void raw_member_setter([[maybe_unused]] Member member, const inst& inst, const arg& arg) { using mt = member_traits; @@ -52,20 +65,10 @@ namespace meta_hpp::detail throw std::logic_error("an attempt to set a member with an incorrect argument type"); } - std::invoke(member, inst.cast()) = arg.cast(); + std::invoke(std::move(member), inst.cast()) = arg.cast(); } } - template < member_kind Member > - bool raw_member_is_gettable_with(const inst_base& inst) { - using mt = member_traits; - using class_type = typename mt::class_type; - - using qualified_type = const class_type; - - return inst.can_cast_to(); - } - template < member_kind Member > bool raw_member_is_settable_with(const inst_base& inst, const arg_base& arg) { using mt = member_traits; @@ -86,19 +89,19 @@ namespace meta_hpp::detail template < member_kind Member > member_state::getter_impl make_member_getter(Member member) { using namespace std::placeholders; - return std::bind(&raw_member_getter, member, _1); - } - - template < member_kind Member > - member_state::setter_impl make_member_setter(Member member) { - using namespace std::placeholders; - return std::bind(&raw_member_setter, member, _1, _2); + return std::bind(&vargs_invoke, std::move(member), _1); } template < member_kind Member > member_state::is_gettable_with_impl make_member_is_gettable_with() { using namespace std::placeholders; - return std::bind(&raw_member_is_gettable_with, _1); + return std::bind(&vargs_is_invocable_with, _1); + } + + template < member_kind Member > + member_state::setter_impl make_member_setter(Member member) { + using namespace std::placeholders; + return std::bind(&raw_member_setter, std::move(member), _1, _2); } template < member_kind Member > @@ -113,8 +116,8 @@ namespace meta_hpp::detail template < member_kind Member > member_state::member_state(member_index index, Member member) : index{std::move(index)} - , getter{make_member_getter(member)} - , setter{make_member_setter(member)} + , getter{make_member_getter(std::move(member))} + , setter{make_member_setter(std::move(member))} , is_gettable_with{make_member_is_gettable_with()} , is_settable_with{make_member_is_settable_with()} {} @@ -153,13 +156,16 @@ namespace meta_hpp template < typename Instance > value member::get(Instance&& instance) const { using namespace detail; - return state_->getter(inst{std::forward(instance)}); + const inst vinst{std::forward(instance)}; + return state_->getter(vinst); } template < typename Instance, typename Value > void member::set(Instance&& instance, Value&& value) const { using namespace detail; - state_->setter(inst{std::forward(instance)}, arg{std::forward(value)}); + const inst vinst{std::forward(instance)}; + const arg vvalue{std::forward(value)}; + state_->setter(vinst, vvalue); } template < typename Instance > @@ -175,24 +181,30 @@ namespace meta_hpp template < typename Instance > [[nodiscard]] bool member::is_gettable_with() const noexcept { using namespace detail; - return state_->is_gettable_with(inst_base{type_list{}}); + const inst_base vinst{type_list{}}; + return state_->is_gettable_with(vinst); } template < typename Instance > [[nodiscard]] bool member::is_gettable_with(Instance&& instance) const noexcept { using namespace detail; - return state_->is_gettable_with(inst{std::forward(instance)}); + const inst_base vinst{std::forward(instance)}; + return state_->is_gettable_with(vinst); } template < typename Instance, typename Value > [[nodiscard]] bool member::is_settable_with() const noexcept { using namespace detail; - return state_->is_settable_with(inst_base{type_list{}}, arg_base{type_list{}}); + const inst_base vinst{type_list{}}; + const arg_base vvalue{type_list{}}; + return state_->is_settable_with(vinst, vvalue); } template < typename Instance, typename Value > [[nodiscard]] bool member::is_settable_with(Instance&& instance, Value&& value) const noexcept { using namespace detail; - return state_->is_settable_with(inst{std::forward(instance)}, arg{std::forward(value)}); + const inst_base vinst{std::forward(instance)}; + const arg_base vvalue{std::forward(value)}; + return state_->is_settable_with(vinst, vvalue); } } diff --git a/headers/meta.hpp/meta_states/method.hpp b/headers/meta.hpp/meta_states/method.hpp index 3719dfd..0ea9b00 100644 --- a/headers/meta.hpp/meta_states/method.hpp +++ b/headers/meta.hpp/meta_states/method.hpp @@ -14,7 +14,7 @@ namespace meta_hpp::detail { template < method_kind Method > - std::optional raw_method_invoke(Method method, const inst& inst, std::span args) { + std::optional vargs_invoke(Method method, const inst& inst, std::span args) { using mt = method_traits; using return_type = typename mt::return_type; using qualified_type = typename mt::qualified_type; @@ -29,7 +29,7 @@ namespace meta_hpp::detail } // NOLINTNEXTLINE(readability-named-parameter) - return std::invoke([&method, &inst, &args](std::index_sequence){ + return std::invoke([method = std::move(method), &inst, &args](std::index_sequence){ if ( !(... && (args.data() + Is)->can_cast_to>()) ) { throw std::logic_error("an attempt to call a method with incorrect argument types"); } @@ -51,7 +51,7 @@ namespace meta_hpp::detail } template < method_kind Method > - bool raw_method_is_invocable_with(const inst_base& inst, std::span args) { + bool vargs_is_invocable_with(const inst_base& inst, std::span args) { using mt = method_traits; using qualified_type = typename mt::qualified_type; using argument_types = typename mt::argument_types; @@ -76,13 +76,13 @@ namespace meta_hpp::detail template < method_kind Method > method_state::invoke_impl make_method_invoke(Method method) { using namespace std::placeholders; - return std::bind(&raw_method_invoke, method, _1, _2); + return std::bind(&vargs_invoke, std::move(method), _1, _2); } template < method_kind Method > method_state::is_invocable_with_impl make_method_is_invocable_with() { using namespace std::placeholders; - return std::bind(&raw_method_is_invocable_with, _1, _2); + return std::bind(&vargs_is_invocable_with, _1, _2); } } @@ -91,7 +91,7 @@ namespace meta_hpp::detail template < method_kind Method > method_state::method_state(method_index index, Method method) : index{std::move(index)} - , invoke{make_method_invoke(method)} + , invoke{make_method_invoke(std::move(method))} , is_invocable_with{make_method_is_invocable_with()} {} template < method_kind Method > @@ -129,11 +129,12 @@ namespace meta_hpp template < typename Instance, typename... Args > std::optional method::invoke(Instance&& instance, Args&&... args) const { using namespace detail; + const inst vinst{std::forward(instance)}; if constexpr ( sizeof...(Args) > 0 ) { - std::array vargs{arg{std::forward(args)}...}; - return state_->invoke(inst{std::forward(instance)}, vargs); + const std::array vargs{arg{std::forward(args)}...}; + return state_->invoke(vinst, vargs); } else { - return state_->invoke(inst{std::forward(instance)}, {}); + return state_->invoke(vinst, {}); } } @@ -145,22 +146,24 @@ namespace meta_hpp template < typename Instance, typename... Args > bool method::is_invocable_with() const noexcept { using namespace detail; + const inst_base vinst{type_list{}}; if constexpr ( sizeof...(Args) > 0 ) { - std::array vargs{arg_base{type_list{}}...}; - return state_->is_invocable_with(inst_base{type_list{}}, vargs); + const std::array vargs{arg_base{type_list{}}...}; + return state_->is_invocable_with(vinst, vargs); } else { - return state_->is_invocable_with(inst_base{type_list{}}, {}); + return state_->is_invocable_with(vinst, {}); } } template < typename Instance, typename... Args > bool method::is_invocable_with(Instance&& instance, Args&&... args) const noexcept { using namespace detail; + const inst_base vinst{std::forward(instance)}; if constexpr ( sizeof...(Args) > 0 ) { - std::array vargs{arg{std::forward(args)}...}; - return state_->is_invocable_with(inst{std::forward(instance)}, vargs); + const std::array vargs{arg_base{std::forward(args)}...}; + return state_->is_invocable_with(vinst, vargs); } else { - return state_->is_invocable_with(inst{std::forward(instance)}, {}); + return state_->is_invocable_with(vinst, {}); } } } diff --git a/headers/meta.hpp/meta_states/variable.hpp b/headers/meta.hpp/meta_states/variable.hpp index 5db678e..0bb8b3c 100644 --- a/headers/meta.hpp/meta_states/variable.hpp +++ b/headers/meta.hpp/meta_states/variable.hpp @@ -117,7 +117,8 @@ namespace meta_hpp template < typename Value > void variable::set(Value&& value) const { using namespace detail; - state_->setter(arg{std::forward(value)}); + const arg vvalue{std::forward(value)}; + state_->setter(vvalue); } inline value variable::operator()() const { @@ -132,12 +133,14 @@ namespace meta_hpp template < typename Value > bool variable::is_settable_with() const noexcept { using namespace detail; - return state_->is_settable_with(arg_base{type_list{}}); + const arg_base vvalue{type_list{}}; + return state_->is_settable_with(vvalue); } template < typename Value > bool variable::is_settable_with(Value&& value) const noexcept { using namespace detail; - return state_->is_settable_with(arg{std::forward(value)}); + const arg vvalue{std::forward(value)}; + return state_->is_settable_with(vvalue); } } diff --git a/headers/meta.hpp/meta_utilities.hpp b/headers/meta.hpp/meta_utilities.hpp index 2ae69d0..27315b2 100644 --- a/headers/meta.hpp/meta_utilities.hpp +++ b/headers/meta.hpp/meta_utilities.hpp @@ -236,6 +236,12 @@ namespace meta_hpp::detail virtual ~arg_base() = default; + template < decay_value_kind T > + explicit arg_base(T&& v); + + template < decay_non_uvalue_kind T > + explicit arg_base(T&& v); + template < arg_lvalue_ref_kind T > requires decay_non_uvalue_kind explicit arg_base(type_list); @@ -313,6 +319,12 @@ namespace meta_hpp::detail virtual ~inst_base() = default; + template < decay_value_kind T > + explicit inst_base(T&& v); + + template < decay_non_uvalue_kind T > + explicit inst_base(T&& v); + template < inst_class_lvalue_ref_kind T > explicit inst_base(type_list); diff --git a/headers/meta.hpp/meta_utilities/arg.hpp b/headers/meta.hpp/meta_utilities/arg.hpp index 529c24e..259bb42 100644 --- a/headers/meta.hpp/meta_utilities/arg.hpp +++ b/headers/meta.hpp/meta_utilities/arg.hpp @@ -11,6 +11,16 @@ namespace meta_hpp::detail { + template < decay_value_kind T > + // NOLINTNEXTLINE(readability-named-parameter) + arg_base::arg_base(T&&) + : arg_base{type_list{}} {} + + template < decay_non_uvalue_kind T > + // NOLINTNEXTLINE(readability-named-parameter) + arg_base::arg_base(T&&) + : arg_base{type_list{}} {} + template < arg_lvalue_ref_kind T > requires decay_non_uvalue_kind // NOLINTNEXTLINE(readability-named-parameter) @@ -174,7 +184,7 @@ namespace meta_hpp::detail template < decay_non_uvalue_kind T > arg::arg(T&& v) - : arg_base{type_list{}} + : arg_base{std::forward(v)} // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) , data_{const_cast*>(std::addressof(v))} {} diff --git a/headers/meta.hpp/meta_utilities/inst.hpp b/headers/meta.hpp/meta_utilities/inst.hpp index c52868a..9c34939 100644 --- a/headers/meta.hpp/meta_utilities/inst.hpp +++ b/headers/meta.hpp/meta_utilities/inst.hpp @@ -62,6 +62,16 @@ namespace meta_hpp::detail namespace meta_hpp::detail { + template < decay_value_kind T > + // NOLINTNEXTLINE(readability-named-parameter) + inst_base::inst_base(T&&) + : inst_base{type_list{}} {} + + template < decay_non_uvalue_kind T > + // NOLINTNEXTLINE(readability-named-parameter) + inst_base::inst_base(T&&) + : inst_base{type_list{}} {} + template < inst_class_lvalue_ref_kind T > // NOLINTNEXTLINE(readability-named-parameter) inst_base::inst_base(type_list) @@ -174,7 +184,7 @@ namespace meta_hpp::detail template < decay_non_uvalue_kind T > inst::inst(T&& v) - : inst_base{type_list{}} + : inst_base{std::forward(v)} // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) , data_{const_cast*>(std::addressof(v))} {} diff --git a/headers/meta.hpp/meta_utilities/vinvoke.hpp b/headers/meta.hpp/meta_utilities/vinvoke.hpp new file mode 100644 index 0000000..65c49c1 --- /dev/null +++ b/headers/meta.hpp/meta_utilities/vinvoke.hpp @@ -0,0 +1,170 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/meta.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#pragma once + +#include "../meta_base.hpp" +#include "../meta_states.hpp" +#include "../meta_utilities.hpp" + +namespace meta_hpp +{ + template < typename... Args > + std::optional invoke(const function& function, Args&&... args) { + return function.invoke(std::forward(args)...); + } + + template < detail::function_kind Function, typename... Args > + std::optional invoke(Function&& function, Args&&... args) { + using namespace detail; + if constexpr ( sizeof...(Args) > 0 ) { + const std::array vargs{arg{std::forward(args)}...}; + return vargs_invoke(std::forward(function), vargs); + } else { + return vargs_invoke(std::forward(function), {}); + } + } +} + +namespace meta_hpp +{ + template < typename Instance > + std::optional invoke(const member& member, Instance&& instance) { + return member.get(std::forward(instance)); + } + + template < detail::member_kind Member, typename Instance > + std::optional invoke(Member&& member, Instance&& instance) { + using namespace detail; + const inst vinst{std::forward(instance)}; + return vargs_invoke(std::forward(member), vinst); + } +} + +namespace meta_hpp +{ + template < typename Instance, typename... Args > + std::optional invoke(const method& method, Instance&& instance, Args&&... args) { + return method.invoke(std::forward(instance), std::forward(args)...); + } + + template < detail::method_kind Method, typename Instance, typename... Args > + std::optional invoke(Method&& method, Instance&& instance, Args&&... args) { + using namespace detail; + const inst vinst{std::forward(instance)}; + if constexpr ( sizeof...(Args) > 0 ) { + const std::array vargs{arg{std::forward(args)}...}; + return vargs_invoke(std::forward(method), vinst, vargs); + } else { + return vargs_invoke(std::forward(method), vinst, {}); + } + } +} + +namespace meta_hpp +{ + template < typename... Args > + bool is_invocable_with(const function& function) { + return function.is_invocable_with(); + } + + template < typename... Args > + bool is_invocable_with(const function& function, Args&&... args) { + return function.is_invocable_with(std::forward(args)...); + } + + template < detail::function_kind Function, typename... Args > + bool is_invocable_with() { + if constexpr ( sizeof...(Args) > 0 ) { + using namespace detail; + const std::array vargs{arg_base{type_list{}}...}; + return vargs_is_invocable_with(vargs); + } else { + return vargs_is_invocable_with({}); + } + } + + template < detail::function_kind Function, typename... Args > + bool is_invocable_with(Args&&... args) { + if constexpr ( sizeof...(Args) > 0 ) { + using namespace detail; + const std::array vargs{arg_base{std::forward(args)}...}; + return vargs_is_invocable_with(vargs); + } else { + return vargs_is_invocable_with({}); + } + } +} + +namespace meta_hpp +{ + template < typename Instance > + bool is_invocable_with(const member& member) { + return member.is_gettable_with(); + } + + template < typename Instance > + bool is_invocable_with(const member& member, Instance&& instance) { + return member.is_gettable_with(std::forward(instance)); + } +} + +namespace meta_hpp +{ + template < typename Instance, typename... Args > + bool is_invocable_with(const method& method) { + return method.is_invocable_with(); + } + + template < typename Instance, typename... Args > + bool is_invocable_with(const method& method, Instance&& instance, Args&&... args) { + return method.is_invocable_with(std::forward(instance), std::forward(args)...); + } +} + +namespace meta_hpp +{ + template < detail::member_kind Member, typename Instance > + bool is_invocable_with() { + using namespace detail; + const inst_base vinst{type_list{}}; + return vargs_is_invocable_with(vinst); + } + + template < detail::member_kind Member, typename Instance > + bool is_invocable_with(Instance&& instance) { + using namespace detail; + const inst_base vinst{std::forward(instance)}; + return vargs_is_invocable_with(vinst); + } +} + +namespace meta_hpp +{ + template < detail::method_kind Method, typename Instance, typename... Args > + bool is_invocable_with() { + using namespace detail; + const inst_base vinst{type_list{}}; + if constexpr ( sizeof...(Args) > 0 ) { + const std::array vargs{arg_base{type_list{}}...}; + return vargs_is_invocable_with(vinst, vargs); + } else { + return vargs_is_invocable_with(vinst, {}); + } + } + + template < detail::method_kind Method, typename Instance, typename... Args > + bool is_invocable_with(Instance&& instance, Args&&... args) { + using namespace detail; + const inst_base vinst{std::forward(instance)}; + if constexpr ( sizeof...(Args) > 0 ) { + const std::array vargs{arg_base{std::forward(args)}...}; + return vargs_is_invocable_with(vinst, vargs); + } else { + return vargs_is_invocable_with(vinst, {}); + } + } +} diff --git a/untests/meta_utilities/arg6_tests.cpp b/untests/meta_utilities/arg6_tests.cpp index 25ea23f..67c09da 100644 --- a/untests/meta_utilities/arg6_tests.cpp +++ b/untests/meta_utilities/arg6_tests.cpp @@ -39,8 +39,6 @@ TEST_CASE("meta/meta_utilities/arg6") { .function_("func_with_method", &func_with_method); SUBCASE("int_member") { - static_assert(sizeof(int_member_t) == 8); - const meta::function f = scope.get_function("func_with_member"); REQUIRE(f); @@ -55,8 +53,6 @@ TEST_CASE("meta/meta_utilities/arg6") { } SUBCASE("int_method") { - static_assert(sizeof(int_method_t) == 16); - const meta::function f = scope.get_function("func_with_method"); REQUIRE(f); diff --git a/untests/meta_utilities/invoke_tests.cpp b/untests/meta_utilities/invoke_tests.cpp new file mode 100644 index 0000000..f13e07b --- /dev/null +++ b/untests/meta_utilities/invoke_tests.cpp @@ -0,0 +1,85 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/meta.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include "../meta_untests.hpp" + +namespace +{ + struct clazz { + int member{1}; + int method(int i) const { return i; } + static int function(int i) { return i; } + }; +} + +TEST_CASE("meta/meta_utilities/invoke") { + namespace meta = meta_hpp; + + meta::class_() + .member_("member", &clazz::member) + .method_("method", &clazz::method) + .function_("function", &clazz::function); + + const meta::class_type& clazz_type = meta::resolve_type(); + REQUIRE(clazz_type); + + const meta::member& clazz_member = clazz_type.get_member("member"); + const meta::method& clazz_method = clazz_type.get_method("method"); + const meta::function& clazz_function = clazz_type.get_function("function"); + REQUIRE((clazz_member && clazz_method && clazz_function)); + + { + CHECK(meta::invoke(&clazz::function, 3) == 3); + CHECK(meta::invoke(&clazz::function, meta::value(3)) == 3); + CHECK(meta::invoke(clazz_function, 3) == 3); + CHECK(meta::invoke(clazz_function, meta::value(3)) == 3); + + CHECK(meta::is_invocable_with(clazz_function, 3)); + CHECK(meta::is_invocable_with(clazz_function, meta::value(3))); + CHECK(meta::is_invocable_with(clazz_function)); + + using function_t = decltype(&clazz::function); + CHECK(meta::is_invocable_with(3)); + CHECK(meta::is_invocable_with(meta::value(3))); + CHECK(meta::is_invocable_with()); + } + + { + clazz cl; + + CHECK(meta::invoke(&clazz::member, cl) == 1); + CHECK(meta::invoke(&clazz::member, meta::value{cl}) == 1); + CHECK(meta::invoke(clazz_member, cl) == 1); + CHECK(meta::invoke(clazz_member, meta::value{cl}) == 1); + + CHECK(meta::is_invocable_with(clazz_member, cl)); + CHECK(meta::is_invocable_with(clazz_member, meta::value{cl})); + CHECK(meta::is_invocable_with(clazz_member)); + + using member_t = decltype(&clazz::member); + CHECK(meta::is_invocable_with(cl)); + CHECK(meta::is_invocable_with(meta::value{cl})); + CHECK(meta::is_invocable_with()); + } + + { + clazz cl; + + CHECK(meta::invoke(&clazz::method, cl, 2) == 2); + CHECK(meta::invoke(&clazz::method, meta::value{cl}, meta::value(2)) == 2); + CHECK(meta::invoke(clazz_method, cl, 2) == 2); + CHECK(meta::invoke(clazz_method, meta::value{cl}, meta::value(2)) == 2); + + CHECK(meta::is_invocable_with(clazz_method, cl, 2)); + CHECK(meta::is_invocable_with(clazz_method, meta::value{cl}, meta::value(2))); + CHECK(meta::is_invocable_with(clazz_method)); + + using method_t = decltype(&clazz::method); + CHECK(meta::is_invocable_with(cl, 2)); + CHECK(meta::is_invocable_with(meta::value{cl}, meta::value(2))); + CHECK(meta::is_invocable_with()); + } +}