mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-15 03:45:30 +07:00
universal meta::invoke
This commit is contained in:
@@ -54,3 +54,4 @@
|
|||||||
#include "meta_utilities/arg.hpp"
|
#include "meta_utilities/arg.hpp"
|
||||||
#include "meta_utilities/inst.hpp"
|
#include "meta_utilities/inst.hpp"
|
||||||
#include "meta_utilities/value.hpp"
|
#include "meta_utilities/value.hpp"
|
||||||
|
#include "meta_utilities/vinvoke.hpp"
|
||||||
|
|||||||
@@ -260,8 +260,8 @@ namespace meta_hpp
|
|||||||
namespace meta_hpp::detail
|
namespace meta_hpp::detail
|
||||||
{
|
{
|
||||||
struct ctor_state final {
|
struct ctor_state final {
|
||||||
using invoke_impl = std::function<value(std::span<arg>)>;
|
using invoke_impl = std::function<value(std::span<const arg>)>;
|
||||||
using is_invocable_with_impl = std::function<bool(std::span<arg_base>)>;
|
using is_invocable_with_impl = std::function<bool(std::span<const arg_base>)>;
|
||||||
|
|
||||||
const ctor_index index;
|
const ctor_index index;
|
||||||
const invoke_impl invoke;
|
const invoke_impl invoke;
|
||||||
@@ -287,8 +287,8 @@ namespace meta_hpp::detail
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct function_state final {
|
struct function_state final {
|
||||||
using invoke_impl = std::function<std::optional<value>(std::span<arg>)>;
|
using invoke_impl = std::function<std::optional<value>(std::span<const arg>)>;
|
||||||
using is_invocable_with_impl = std::function<bool(std::span<arg_base>)>;
|
using is_invocable_with_impl = std::function<bool(std::span<const arg_base>)>;
|
||||||
|
|
||||||
const function_index index;
|
const function_index index;
|
||||||
const invoke_impl invoke;
|
const invoke_impl invoke;
|
||||||
@@ -322,8 +322,8 @@ namespace meta_hpp::detail
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct method_state final {
|
struct method_state final {
|
||||||
using invoke_impl = std::function<std::optional<value>(const inst&, std::span<arg>)>;
|
using invoke_impl = std::function<std::optional<value>(const inst&, std::span<const arg>)>;
|
||||||
using is_invocable_with_impl = std::function<bool(const inst_base&, std::span<arg_base>)>;
|
using is_invocable_with_impl = std::function<bool(const inst_base&, std::span<const arg_base>)>;
|
||||||
|
|
||||||
const method_index index;
|
const method_index index;
|
||||||
const invoke_impl invoke;
|
const invoke_impl invoke;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
namespace meta_hpp::detail
|
namespace meta_hpp::detail
|
||||||
{
|
{
|
||||||
template < class_kind Class, typename... Args >
|
template < class_kind Class, typename... Args >
|
||||||
value raw_ctor_invoke(std::span<arg> args) {
|
value vargs_invoke(std::span<const arg> args) {
|
||||||
using ct = ctor_traits<Class, Args...>;
|
using ct = ctor_traits<Class, Args...>;
|
||||||
using class_type = typename ct::class_type;
|
using class_type = typename ct::class_type;
|
||||||
using argument_types = typename ct::argument_types;
|
using argument_types = typename ct::argument_types;
|
||||||
@@ -35,7 +35,7 @@ namespace meta_hpp::detail
|
|||||||
}
|
}
|
||||||
|
|
||||||
template < class_kind Class, typename... Args >
|
template < class_kind Class, typename... Args >
|
||||||
bool raw_ctor_is_invocable_with(std::span<arg_base> args) {
|
bool vargs_is_invocable_with(std::span<const arg_base> args) {
|
||||||
using ct = ctor_traits<Class, Args...>;
|
using ct = ctor_traits<Class, Args...>;
|
||||||
using argument_types = typename ct::argument_types;
|
using argument_types = typename ct::argument_types;
|
||||||
|
|
||||||
@@ -55,13 +55,13 @@ namespace meta_hpp::detail
|
|||||||
template < class_kind Class, typename... Args >
|
template < class_kind Class, typename... Args >
|
||||||
ctor_state::invoke_impl make_ctor_invoke() {
|
ctor_state::invoke_impl make_ctor_invoke() {
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
return std::bind(&raw_ctor_invoke<Class, Args...>, _1);
|
return std::bind(&vargs_invoke<Class, Args...>, _1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template < class_kind Class, typename... Args >
|
template < class_kind Class, typename... Args >
|
||||||
ctor_state::is_invocable_with_impl make_ctor_is_invocable_with() {
|
ctor_state::is_invocable_with_impl make_ctor_is_invocable_with() {
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
return std::bind(&raw_ctor_is_invocable_with<Class, Args...>, _1);
|
return std::bind(&vargs_is_invocable_with<Class, Args...>, _1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,9 +104,9 @@ namespace meta_hpp
|
|||||||
|
|
||||||
template < typename... Args >
|
template < typename... Args >
|
||||||
value ctor::invoke(Args&&... args) const {
|
value ctor::invoke(Args&&... args) const {
|
||||||
using namespace detail;
|
|
||||||
if constexpr ( sizeof...(Args) > 0 ) {
|
if constexpr ( sizeof...(Args) > 0 ) {
|
||||||
std::array<arg, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
|
using namespace detail;
|
||||||
|
const std::array<arg, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
|
||||||
return state_->invoke(vargs);
|
return state_->invoke(vargs);
|
||||||
} else {
|
} else {
|
||||||
return state_->invoke({});
|
return state_->invoke({});
|
||||||
@@ -120,9 +120,9 @@ namespace meta_hpp
|
|||||||
|
|
||||||
template < typename... Args >
|
template < typename... Args >
|
||||||
bool ctor::is_invocable_with() const noexcept {
|
bool ctor::is_invocable_with() const noexcept {
|
||||||
using namespace detail;
|
|
||||||
if constexpr ( sizeof...(Args) > 0 ) {
|
if constexpr ( sizeof...(Args) > 0 ) {
|
||||||
std::array<arg_base, sizeof...(Args)> vargs{arg_base{type_list<Args>{}}...};
|
using namespace detail;
|
||||||
|
const std::array<arg_base, sizeof...(Args)> vargs{arg_base{type_list<Args>{}}...};
|
||||||
return state_->is_invocable_with(vargs);
|
return state_->is_invocable_with(vargs);
|
||||||
} else {
|
} else {
|
||||||
return state_->is_invocable_with({});
|
return state_->is_invocable_with({});
|
||||||
@@ -131,9 +131,9 @@ namespace meta_hpp
|
|||||||
|
|
||||||
template < typename... Args >
|
template < typename... Args >
|
||||||
bool ctor::is_invocable_with(Args&&... args) const noexcept {
|
bool ctor::is_invocable_with(Args&&... args) const noexcept {
|
||||||
using namespace detail;
|
|
||||||
if constexpr ( sizeof...(Args) > 0 ) {
|
if constexpr ( sizeof...(Args) > 0 ) {
|
||||||
std::array<arg_base, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
|
using namespace detail;
|
||||||
|
const std::array<arg_base, sizeof...(Args)> vargs{arg_base{std::forward<Args>(args)}...};
|
||||||
return state_->is_invocable_with(vargs);
|
return state_->is_invocable_with(vargs);
|
||||||
} else {
|
} else {
|
||||||
return state_->is_invocable_with({});
|
return state_->is_invocable_with({});
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
namespace meta_hpp::detail
|
namespace meta_hpp::detail
|
||||||
{
|
{
|
||||||
template < function_kind Function >
|
template < function_kind Function >
|
||||||
std::optional<value> raw_function_invoke(Function function, std::span<arg> args) {
|
std::optional<value> vargs_invoke(Function function, std::span<const arg> args) {
|
||||||
using ft = function_traits<Function>;
|
using ft = function_traits<Function>;
|
||||||
using return_type = typename ft::return_type;
|
using return_type = typename ft::return_type;
|
||||||
using argument_types = typename ft::argument_types;
|
using argument_types = typename ft::argument_types;
|
||||||
@@ -24,7 +24,7 @@ namespace meta_hpp::detail
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(readability-named-parameter)
|
// NOLINTNEXTLINE(readability-named-parameter)
|
||||||
return std::invoke([&function, &args]<std::size_t... Is>(std::index_sequence<Is...>){
|
return std::invoke([function = std::move(function), &args]<std::size_t... Is>(std::index_sequence<Is...>){
|
||||||
if ( !(... && (args.data() + Is)->can_cast_to<type_list_at_t<Is, argument_types>>()) ) {
|
if ( !(... && (args.data() + Is)->can_cast_to<type_list_at_t<Is, argument_types>>()) ) {
|
||||||
throw std::logic_error("an attempt to call a function with incorrect argument types");
|
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 >
|
template < function_kind Function >
|
||||||
bool raw_function_is_invocable_with(std::span<arg_base> args) {
|
bool vargs_is_invocable_with(std::span<const arg_base> args) {
|
||||||
using ft = function_traits<Function>;
|
using ft = function_traits<Function>;
|
||||||
using argument_types = typename ft::argument_types;
|
using argument_types = typename ft::argument_types;
|
||||||
|
|
||||||
@@ -64,13 +64,13 @@ namespace meta_hpp::detail
|
|||||||
template < function_kind Function >
|
template < function_kind Function >
|
||||||
function_state::invoke_impl make_function_invoke(Function function) {
|
function_state::invoke_impl make_function_invoke(Function function) {
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
return std::bind(&raw_function_invoke<Function>, function, _1);
|
return std::bind(&vargs_invoke<Function>, std::move(function), _1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template < function_kind Function >
|
template < function_kind Function >
|
||||||
function_state::is_invocable_with_impl make_function_is_invocable_with() {
|
function_state::is_invocable_with_impl make_function_is_invocable_with() {
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
return std::bind(&raw_function_is_invocable_with<Function>, _1);
|
return std::bind(&vargs_is_invocable_with<Function>, _1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ namespace meta_hpp::detail
|
|||||||
template < function_kind Function >
|
template < function_kind Function >
|
||||||
function_state::function_state(function_index index, Function function)
|
function_state::function_state(function_index index, Function function)
|
||||||
: index{std::move(index)}
|
: index{std::move(index)}
|
||||||
, invoke{make_function_invoke(function)}
|
, invoke{make_function_invoke(std::move(function))}
|
||||||
, is_invocable_with{make_function_is_invocable_with<Function>()} {}
|
, is_invocable_with{make_function_is_invocable_with<Function>()} {}
|
||||||
|
|
||||||
template < function_kind Function >
|
template < function_kind Function >
|
||||||
@@ -116,9 +116,9 @@ namespace meta_hpp
|
|||||||
|
|
||||||
template < typename... Args >
|
template < typename... Args >
|
||||||
std::optional<value> function::invoke(Args&&... args) const {
|
std::optional<value> function::invoke(Args&&... args) const {
|
||||||
using namespace detail;
|
|
||||||
if constexpr ( sizeof...(Args) > 0 ) {
|
if constexpr ( sizeof...(Args) > 0 ) {
|
||||||
std::array<arg, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
|
using namespace detail;
|
||||||
|
const std::array<arg, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
|
||||||
return state_->invoke(vargs);
|
return state_->invoke(vargs);
|
||||||
} else {
|
} else {
|
||||||
return state_->invoke({});
|
return state_->invoke({});
|
||||||
@@ -132,9 +132,9 @@ namespace meta_hpp
|
|||||||
|
|
||||||
template < typename... Args >
|
template < typename... Args >
|
||||||
bool function::is_invocable_with() const noexcept {
|
bool function::is_invocable_with() const noexcept {
|
||||||
using namespace detail;
|
|
||||||
if constexpr ( sizeof...(Args) > 0 ) {
|
if constexpr ( sizeof...(Args) > 0 ) {
|
||||||
std::array<arg_base, sizeof...(Args)> vargs{arg_base{type_list<Args>{}}...};
|
using namespace detail;
|
||||||
|
const std::array<arg_base, sizeof...(Args)> vargs{arg_base{type_list<Args>{}}...};
|
||||||
return state_->is_invocable_with(vargs);
|
return state_->is_invocable_with(vargs);
|
||||||
} else {
|
} else {
|
||||||
return state_->is_invocable_with({});
|
return state_->is_invocable_with({});
|
||||||
@@ -143,9 +143,9 @@ namespace meta_hpp
|
|||||||
|
|
||||||
template < typename... Args >
|
template < typename... Args >
|
||||||
bool function::is_invocable_with(Args&&... args) const noexcept {
|
bool function::is_invocable_with(Args&&... args) const noexcept {
|
||||||
using namespace detail;
|
|
||||||
if constexpr ( sizeof...(Args) > 0 ) {
|
if constexpr ( sizeof...(Args) > 0 ) {
|
||||||
std::array<arg_base, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
|
using namespace detail;
|
||||||
|
const std::array<arg_base, sizeof...(Args)> vargs{arg_base{std::forward<Args>(args)}...};
|
||||||
return state_->is_invocable_with(vargs);
|
return state_->is_invocable_with(vargs);
|
||||||
} else {
|
} else {
|
||||||
return state_->is_invocable_with({});
|
return state_->is_invocable_with({});
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
namespace meta_hpp::detail
|
namespace meta_hpp::detail
|
||||||
{
|
{
|
||||||
template < member_kind Member >
|
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<Member>;
|
using mt = member_traits<Member>;
|
||||||
using class_type = typename mt::class_type;
|
using class_type = typename mt::class_type;
|
||||||
using value_type = typename mt::value_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");
|
throw std::logic_error("an attempt to get a member with an incorrect instance type");
|
||||||
}
|
}
|
||||||
|
|
||||||
value_type return_value{std::invoke(member, inst.cast<qualified_type>())};
|
value_type return_value{std::invoke(std::move(member), inst.cast<qualified_type>())};
|
||||||
return value{std::forward<value_type>(return_value)};
|
return value{std::forward<value_type>(return_value)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template < member_kind Member >
|
||||||
|
bool vargs_is_invocable_with(const inst_base& inst) {
|
||||||
|
using mt = member_traits<Member>;
|
||||||
|
using class_type = typename mt::class_type;
|
||||||
|
|
||||||
|
using qualified_type = const class_type;
|
||||||
|
|
||||||
|
return inst.can_cast_to<qualified_type>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace meta_hpp::detail
|
||||||
|
{
|
||||||
template < member_kind Member >
|
template < member_kind Member >
|
||||||
void raw_member_setter([[maybe_unused]] Member member, const inst& inst, const arg& arg) {
|
void raw_member_setter([[maybe_unused]] Member member, const inst& inst, const arg& arg) {
|
||||||
using mt = member_traits<Member>;
|
using mt = member_traits<Member>;
|
||||||
@@ -52,20 +65,10 @@ namespace meta_hpp::detail
|
|||||||
throw std::logic_error("an attempt to set a member with an incorrect argument type");
|
throw std::logic_error("an attempt to set a member with an incorrect argument type");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::invoke(member, inst.cast<qualified_type>()) = arg.cast<value_type>();
|
std::invoke(std::move(member), inst.cast<qualified_type>()) = arg.cast<value_type>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template < member_kind Member >
|
|
||||||
bool raw_member_is_gettable_with(const inst_base& inst) {
|
|
||||||
using mt = member_traits<Member>;
|
|
||||||
using class_type = typename mt::class_type;
|
|
||||||
|
|
||||||
using qualified_type = const class_type;
|
|
||||||
|
|
||||||
return inst.can_cast_to<qualified_type>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template < member_kind Member >
|
template < member_kind Member >
|
||||||
bool raw_member_is_settable_with(const inst_base& inst, const arg_base& arg) {
|
bool raw_member_is_settable_with(const inst_base& inst, const arg_base& arg) {
|
||||||
using mt = member_traits<Member>;
|
using mt = member_traits<Member>;
|
||||||
@@ -86,19 +89,19 @@ namespace meta_hpp::detail
|
|||||||
template < member_kind Member >
|
template < member_kind Member >
|
||||||
member_state::getter_impl make_member_getter(Member member) {
|
member_state::getter_impl make_member_getter(Member member) {
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
return std::bind(&raw_member_getter<Member>, member, _1);
|
return std::bind(&vargs_invoke<Member>, std::move(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>, member, _1, _2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template < member_kind Member >
|
template < member_kind Member >
|
||||||
member_state::is_gettable_with_impl make_member_is_gettable_with() {
|
member_state::is_gettable_with_impl make_member_is_gettable_with() {
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
return std::bind(&raw_member_is_gettable_with<Member>, _1);
|
return std::bind(&vargs_is_invocable_with<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>, std::move(member), _1, _2);
|
||||||
}
|
}
|
||||||
|
|
||||||
template < member_kind Member >
|
template < member_kind Member >
|
||||||
@@ -113,8 +116,8 @@ namespace meta_hpp::detail
|
|||||||
template < member_kind Member >
|
template < member_kind Member >
|
||||||
member_state::member_state(member_index index, Member member)
|
member_state::member_state(member_index index, Member member)
|
||||||
: index{std::move(index)}
|
: index{std::move(index)}
|
||||||
, getter{make_member_getter(member)}
|
, getter{make_member_getter(std::move(member))}
|
||||||
, setter{make_member_setter(member)}
|
, setter{make_member_setter(std::move(member))}
|
||||||
, is_gettable_with{make_member_is_gettable_with<Member>()}
|
, is_gettable_with{make_member_is_gettable_with<Member>()}
|
||||||
, is_settable_with{make_member_is_settable_with<Member>()} {}
|
, is_settable_with{make_member_is_settable_with<Member>()} {}
|
||||||
|
|
||||||
@@ -153,13 +156,16 @@ namespace meta_hpp
|
|||||||
template < typename Instance >
|
template < typename Instance >
|
||||||
value member::get(Instance&& instance) const {
|
value member::get(Instance&& instance) const {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
return state_->getter(inst{std::forward<Instance>(instance)});
|
const inst vinst{std::forward<Instance>(instance)};
|
||||||
|
return state_->getter(vinst);
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename Instance, typename Value >
|
template < typename Instance, typename Value >
|
||||||
void member::set(Instance&& instance, Value&& value) const {
|
void member::set(Instance&& instance, Value&& value) const {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
state_->setter(inst{std::forward<Instance>(instance)}, arg{std::forward<Value>(value)});
|
const inst vinst{std::forward<Instance>(instance)};
|
||||||
|
const arg vvalue{std::forward<Value>(value)};
|
||||||
|
state_->setter(vinst, vvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename Instance >
|
template < typename Instance >
|
||||||
@@ -175,24 +181,30 @@ namespace meta_hpp
|
|||||||
template < typename Instance >
|
template < typename Instance >
|
||||||
[[nodiscard]] bool member::is_gettable_with() const noexcept {
|
[[nodiscard]] bool member::is_gettable_with() const noexcept {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
return state_->is_gettable_with(inst_base{type_list<Instance>{}});
|
const inst_base vinst{type_list<Instance>{}};
|
||||||
|
return state_->is_gettable_with(vinst);
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename Instance >
|
template < typename Instance >
|
||||||
[[nodiscard]] bool member::is_gettable_with(Instance&& instance) const noexcept {
|
[[nodiscard]] bool member::is_gettable_with(Instance&& instance) const noexcept {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
return state_->is_gettable_with(inst{std::forward<Instance>(instance)});
|
const inst_base vinst{std::forward<Instance>(instance)};
|
||||||
|
return state_->is_gettable_with(vinst);
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename Instance, typename Value >
|
template < typename Instance, typename Value >
|
||||||
[[nodiscard]] bool member::is_settable_with() const noexcept {
|
[[nodiscard]] bool member::is_settable_with() const noexcept {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
return state_->is_settable_with(inst_base{type_list<Instance>{}}, arg_base{type_list<Value>{}});
|
const inst_base vinst{type_list<Instance>{}};
|
||||||
|
const arg_base vvalue{type_list<Value>{}};
|
||||||
|
return state_->is_settable_with(vinst, vvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename Instance, typename Value >
|
template < typename Instance, typename Value >
|
||||||
[[nodiscard]] bool member::is_settable_with(Instance&& instance, Value&& value) const noexcept {
|
[[nodiscard]] bool member::is_settable_with(Instance&& instance, Value&& value) const noexcept {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
return state_->is_settable_with(inst{std::forward<Instance>(instance)}, arg{std::forward<Value>(value)});
|
const inst_base vinst{std::forward<Instance>(instance)};
|
||||||
|
const arg_base vvalue{std::forward<Value>(value)};
|
||||||
|
return state_->is_settable_with(vinst, vvalue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
namespace meta_hpp::detail
|
namespace meta_hpp::detail
|
||||||
{
|
{
|
||||||
template < method_kind Method >
|
template < method_kind Method >
|
||||||
std::optional<value> raw_method_invoke(Method method, const inst& inst, std::span<arg> args) {
|
std::optional<value> vargs_invoke(Method method, const inst& inst, std::span<const arg> args) {
|
||||||
using mt = method_traits<Method>;
|
using mt = method_traits<Method>;
|
||||||
using return_type = typename mt::return_type;
|
using return_type = typename mt::return_type;
|
||||||
using qualified_type = typename mt::qualified_type;
|
using qualified_type = typename mt::qualified_type;
|
||||||
@@ -29,7 +29,7 @@ namespace meta_hpp::detail
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(readability-named-parameter)
|
// NOLINTNEXTLINE(readability-named-parameter)
|
||||||
return std::invoke([&method, &inst, &args]<std::size_t... Is>(std::index_sequence<Is...>){
|
return std::invoke([method = std::move(method), &inst, &args]<std::size_t... Is>(std::index_sequence<Is...>){
|
||||||
if ( !(... && (args.data() + Is)->can_cast_to<type_list_at_t<Is, argument_types>>()) ) {
|
if ( !(... && (args.data() + Is)->can_cast_to<type_list_at_t<Is, argument_types>>()) ) {
|
||||||
throw std::logic_error("an attempt to call a method with incorrect argument types");
|
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 >
|
template < method_kind Method >
|
||||||
bool raw_method_is_invocable_with(const inst_base& inst, std::span<arg_base> args) {
|
bool vargs_is_invocable_with(const inst_base& inst, std::span<const arg_base> args) {
|
||||||
using mt = method_traits<Method>;
|
using mt = method_traits<Method>;
|
||||||
using qualified_type = typename mt::qualified_type;
|
using qualified_type = typename mt::qualified_type;
|
||||||
using argument_types = typename mt::argument_types;
|
using argument_types = typename mt::argument_types;
|
||||||
@@ -76,13 +76,13 @@ namespace meta_hpp::detail
|
|||||||
template < method_kind Method >
|
template < method_kind Method >
|
||||||
method_state::invoke_impl make_method_invoke(Method method) {
|
method_state::invoke_impl make_method_invoke(Method method) {
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
return std::bind(&raw_method_invoke<Method>, method, _1, _2);
|
return std::bind(&vargs_invoke<Method>, std::move(method), _1, _2);
|
||||||
}
|
}
|
||||||
|
|
||||||
template < method_kind Method >
|
template < method_kind Method >
|
||||||
method_state::is_invocable_with_impl make_method_is_invocable_with() {
|
method_state::is_invocable_with_impl make_method_is_invocable_with() {
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
return std::bind(&raw_method_is_invocable_with<Method>, _1, _2);
|
return std::bind(&vargs_is_invocable_with<Method>, _1, _2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ namespace meta_hpp::detail
|
|||||||
template < method_kind Method >
|
template < method_kind Method >
|
||||||
method_state::method_state(method_index index, Method method)
|
method_state::method_state(method_index index, Method method)
|
||||||
: index{std::move(index)}
|
: index{std::move(index)}
|
||||||
, invoke{make_method_invoke(method)}
|
, invoke{make_method_invoke(std::move(method))}
|
||||||
, is_invocable_with{make_method_is_invocable_with<Method>()} {}
|
, is_invocable_with{make_method_is_invocable_with<Method>()} {}
|
||||||
|
|
||||||
template < method_kind Method >
|
template < method_kind Method >
|
||||||
@@ -129,11 +129,12 @@ namespace meta_hpp
|
|||||||
template < typename Instance, typename... Args >
|
template < typename Instance, typename... Args >
|
||||||
std::optional<value> method::invoke(Instance&& instance, Args&&... args) const {
|
std::optional<value> method::invoke(Instance&& instance, Args&&... args) const {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
|
const inst vinst{std::forward<Instance>(instance)};
|
||||||
if constexpr ( sizeof...(Args) > 0 ) {
|
if constexpr ( sizeof...(Args) > 0 ) {
|
||||||
std::array<arg, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
|
const std::array<arg, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
|
||||||
return state_->invoke(inst{std::forward<Instance>(instance)}, vargs);
|
return state_->invoke(vinst, vargs);
|
||||||
} else {
|
} else {
|
||||||
return state_->invoke(inst{std::forward<Instance>(instance)}, {});
|
return state_->invoke(vinst, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,22 +146,24 @@ namespace meta_hpp
|
|||||||
template < typename Instance, typename... Args >
|
template < typename Instance, typename... Args >
|
||||||
bool method::is_invocable_with() const noexcept {
|
bool method::is_invocable_with() const noexcept {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
|
const inst_base vinst{type_list<Instance>{}};
|
||||||
if constexpr ( sizeof...(Args) > 0 ) {
|
if constexpr ( sizeof...(Args) > 0 ) {
|
||||||
std::array<arg_base, sizeof...(Args)> vargs{arg_base{type_list<Args>{}}...};
|
const std::array<arg_base, sizeof...(Args)> vargs{arg_base{type_list<Args>{}}...};
|
||||||
return state_->is_invocable_with(inst_base{type_list<Instance>{}}, vargs);
|
return state_->is_invocable_with(vinst, vargs);
|
||||||
} else {
|
} else {
|
||||||
return state_->is_invocable_with(inst_base{type_list<Instance>{}}, {});
|
return state_->is_invocable_with(vinst, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename Instance, typename... Args >
|
template < typename Instance, typename... Args >
|
||||||
bool method::is_invocable_with(Instance&& instance, Args&&... args) const noexcept {
|
bool method::is_invocable_with(Instance&& instance, Args&&... args) const noexcept {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
|
const inst_base vinst{std::forward<Instance>(instance)};
|
||||||
if constexpr ( sizeof...(Args) > 0 ) {
|
if constexpr ( sizeof...(Args) > 0 ) {
|
||||||
std::array<arg_base, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
|
const std::array<arg_base, sizeof...(Args)> vargs{arg_base{std::forward<Args>(args)}...};
|
||||||
return state_->is_invocable_with(inst{std::forward<Instance>(instance)}, vargs);
|
return state_->is_invocable_with(vinst, vargs);
|
||||||
} else {
|
} else {
|
||||||
return state_->is_invocable_with(inst{std::forward<Instance>(instance)}, {});
|
return state_->is_invocable_with(vinst, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,7 +117,8 @@ namespace meta_hpp
|
|||||||
template < typename Value >
|
template < typename Value >
|
||||||
void variable::set(Value&& value) const {
|
void variable::set(Value&& value) const {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
state_->setter(arg{std::forward<Value>(value)});
|
const arg vvalue{std::forward<Value>(value)};
|
||||||
|
state_->setter(vvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline value variable::operator()() const {
|
inline value variable::operator()() const {
|
||||||
@@ -132,12 +133,14 @@ namespace meta_hpp
|
|||||||
template < typename Value >
|
template < typename Value >
|
||||||
bool variable::is_settable_with() const noexcept {
|
bool variable::is_settable_with() const noexcept {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
return state_->is_settable_with(arg_base{type_list<Value>{}});
|
const arg_base vvalue{type_list<Value>{}};
|
||||||
|
return state_->is_settable_with(vvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename Value >
|
template < typename Value >
|
||||||
bool variable::is_settable_with(Value&& value) const noexcept {
|
bool variable::is_settable_with(Value&& value) const noexcept {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
return state_->is_settable_with(arg{std::forward<Value>(value)});
|
const arg vvalue{std::forward<Value>(value)};
|
||||||
|
return state_->is_settable_with(vvalue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -236,6 +236,12 @@ namespace meta_hpp::detail
|
|||||||
|
|
||||||
virtual ~arg_base() = default;
|
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 >
|
template < arg_lvalue_ref_kind T >
|
||||||
requires decay_non_uvalue_kind<T>
|
requires decay_non_uvalue_kind<T>
|
||||||
explicit arg_base(type_list<T>);
|
explicit arg_base(type_list<T>);
|
||||||
@@ -313,6 +319,12 @@ namespace meta_hpp::detail
|
|||||||
|
|
||||||
virtual ~inst_base() = default;
|
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 >
|
template < inst_class_lvalue_ref_kind T >
|
||||||
explicit inst_base(type_list<T>);
|
explicit inst_base(type_list<T>);
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,16 @@
|
|||||||
|
|
||||||
namespace meta_hpp::detail
|
namespace meta_hpp::detail
|
||||||
{
|
{
|
||||||
|
template < decay_value_kind T >
|
||||||
|
// NOLINTNEXTLINE(readability-named-parameter)
|
||||||
|
arg_base::arg_base(T&&)
|
||||||
|
: arg_base{type_list<T&&>{}} {}
|
||||||
|
|
||||||
|
template < decay_non_uvalue_kind T >
|
||||||
|
// NOLINTNEXTLINE(readability-named-parameter)
|
||||||
|
arg_base::arg_base(T&&)
|
||||||
|
: arg_base{type_list<T&&>{}} {}
|
||||||
|
|
||||||
template < arg_lvalue_ref_kind T >
|
template < arg_lvalue_ref_kind T >
|
||||||
requires decay_non_uvalue_kind<T>
|
requires decay_non_uvalue_kind<T>
|
||||||
// NOLINTNEXTLINE(readability-named-parameter)
|
// NOLINTNEXTLINE(readability-named-parameter)
|
||||||
@@ -174,7 +184,7 @@ namespace meta_hpp::detail
|
|||||||
|
|
||||||
template < decay_non_uvalue_kind T >
|
template < decay_non_uvalue_kind T >
|
||||||
arg::arg(T&& v)
|
arg::arg(T&& v)
|
||||||
: arg_base{type_list<T&&>{}}
|
: arg_base{std::forward<T>(v)}
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||||
, data_{const_cast<std::remove_cvref_t<T>*>(std::addressof(v))} {}
|
, data_{const_cast<std::remove_cvref_t<T>*>(std::addressof(v))} {}
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,16 @@ namespace meta_hpp::detail
|
|||||||
|
|
||||||
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<T&&>{}} {}
|
||||||
|
|
||||||
|
template < decay_non_uvalue_kind T >
|
||||||
|
// NOLINTNEXTLINE(readability-named-parameter)
|
||||||
|
inst_base::inst_base(T&&)
|
||||||
|
: inst_base{type_list<T&&>{}} {}
|
||||||
|
|
||||||
template < inst_class_lvalue_ref_kind T >
|
template < inst_class_lvalue_ref_kind T >
|
||||||
// NOLINTNEXTLINE(readability-named-parameter)
|
// NOLINTNEXTLINE(readability-named-parameter)
|
||||||
inst_base::inst_base(type_list<T>)
|
inst_base::inst_base(type_list<T>)
|
||||||
@@ -174,7 +184,7 @@ namespace meta_hpp::detail
|
|||||||
|
|
||||||
template < decay_non_uvalue_kind T >
|
template < decay_non_uvalue_kind T >
|
||||||
inst::inst(T&& v)
|
inst::inst(T&& v)
|
||||||
: inst_base{type_list<T&&>{}}
|
: inst_base{std::forward<T>(v)}
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||||
, data_{const_cast<std::remove_cvref_t<T>*>(std::addressof(v))} {}
|
, data_{const_cast<std::remove_cvref_t<T>*>(std::addressof(v))} {}
|
||||||
|
|
||||||
|
|||||||
170
headers/meta.hpp/meta_utilities/vinvoke.hpp
Normal file
170
headers/meta.hpp/meta_utilities/vinvoke.hpp
Normal file
@@ -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<value> invoke(const function& function, Args&&... args) {
|
||||||
|
return function.invoke(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < detail::function_kind Function, typename... Args >
|
||||||
|
std::optional<value> invoke(Function&& function, Args&&... args) {
|
||||||
|
using namespace detail;
|
||||||
|
if constexpr ( sizeof...(Args) > 0 ) {
|
||||||
|
const std::array<arg, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
|
||||||
|
return vargs_invoke(std::forward<Function>(function), vargs);
|
||||||
|
} else {
|
||||||
|
return vargs_invoke(std::forward<Function>(function), {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace meta_hpp
|
||||||
|
{
|
||||||
|
template < typename Instance >
|
||||||
|
std::optional<value> invoke(const member& member, Instance&& instance) {
|
||||||
|
return member.get(std::forward<Instance>(instance));
|
||||||
|
}
|
||||||
|
|
||||||
|
template < detail::member_kind Member, typename Instance >
|
||||||
|
std::optional<value> invoke(Member&& member, Instance&& instance) {
|
||||||
|
using namespace detail;
|
||||||
|
const inst vinst{std::forward<Instance>(instance)};
|
||||||
|
return vargs_invoke(std::forward<Member>(member), vinst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace meta_hpp
|
||||||
|
{
|
||||||
|
template < typename Instance, typename... Args >
|
||||||
|
std::optional<value> invoke(const method& method, Instance&& instance, Args&&... args) {
|
||||||
|
return method.invoke(std::forward<Instance>(instance), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < detail::method_kind Method, typename Instance, typename... Args >
|
||||||
|
std::optional<value> invoke(Method&& method, Instance&& instance, Args&&... args) {
|
||||||
|
using namespace detail;
|
||||||
|
const inst vinst{std::forward<Instance>(instance)};
|
||||||
|
if constexpr ( sizeof...(Args) > 0 ) {
|
||||||
|
const std::array<arg, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
|
||||||
|
return vargs_invoke(std::forward<Method>(method), vinst, vargs);
|
||||||
|
} else {
|
||||||
|
return vargs_invoke(std::forward<Method>(method), vinst, {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace meta_hpp
|
||||||
|
{
|
||||||
|
template < typename... Args >
|
||||||
|
bool is_invocable_with(const function& function) {
|
||||||
|
return function.is_invocable_with<Args...>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename... Args >
|
||||||
|
bool is_invocable_with(const function& function, Args&&... args) {
|
||||||
|
return function.is_invocable_with(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < detail::function_kind Function, typename... Args >
|
||||||
|
bool is_invocable_with() {
|
||||||
|
if constexpr ( sizeof...(Args) > 0 ) {
|
||||||
|
using namespace detail;
|
||||||
|
const std::array<arg_base, sizeof...(Args)> vargs{arg_base{type_list<Args>{}}...};
|
||||||
|
return vargs_is_invocable_with<Function>(vargs);
|
||||||
|
} else {
|
||||||
|
return vargs_is_invocable_with<Function>({});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template < detail::function_kind Function, typename... Args >
|
||||||
|
bool is_invocable_with(Args&&... args) {
|
||||||
|
if constexpr ( sizeof...(Args) > 0 ) {
|
||||||
|
using namespace detail;
|
||||||
|
const std::array<arg_base, sizeof...(Args)> vargs{arg_base{std::forward<Args>(args)}...};
|
||||||
|
return vargs_is_invocable_with<Function>(vargs);
|
||||||
|
} else {
|
||||||
|
return vargs_is_invocable_with<Function>({});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace meta_hpp
|
||||||
|
{
|
||||||
|
template < typename Instance >
|
||||||
|
bool is_invocable_with(const member& member) {
|
||||||
|
return member.is_gettable_with<Instance>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Instance >
|
||||||
|
bool is_invocable_with(const member& member, Instance&& instance) {
|
||||||
|
return member.is_gettable_with(std::forward<Instance>(instance));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace meta_hpp
|
||||||
|
{
|
||||||
|
template < typename Instance, typename... Args >
|
||||||
|
bool is_invocable_with(const method& method) {
|
||||||
|
return method.is_invocable_with<Instance, Args...>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Instance, typename... Args >
|
||||||
|
bool is_invocable_with(const method& method, Instance&& instance, Args&&... args) {
|
||||||
|
return method.is_invocable_with(std::forward<Instance>(instance), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace meta_hpp
|
||||||
|
{
|
||||||
|
template < detail::member_kind Member, typename Instance >
|
||||||
|
bool is_invocable_with() {
|
||||||
|
using namespace detail;
|
||||||
|
const inst_base vinst{type_list<Instance>{}};
|
||||||
|
return vargs_is_invocable_with<Member>(vinst);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < detail::member_kind Member, typename Instance >
|
||||||
|
bool is_invocable_with(Instance&& instance) {
|
||||||
|
using namespace detail;
|
||||||
|
const inst_base vinst{std::forward<Instance>(instance)};
|
||||||
|
return vargs_is_invocable_with<Member>(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<Instance>{}};
|
||||||
|
if constexpr ( sizeof...(Args) > 0 ) {
|
||||||
|
const std::array<arg_base, sizeof...(Args)> vargs{arg_base{type_list<Args>{}}...};
|
||||||
|
return vargs_is_invocable_with<Method>(vinst, vargs);
|
||||||
|
} else {
|
||||||
|
return vargs_is_invocable_with<Method>(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>(instance)};
|
||||||
|
if constexpr ( sizeof...(Args) > 0 ) {
|
||||||
|
const std::array<arg_base, sizeof...(Args)> vargs{arg_base{std::forward<Args>(args)}...};
|
||||||
|
return vargs_is_invocable_with<Method>(vinst, vargs);
|
||||||
|
} else {
|
||||||
|
return vargs_is_invocable_with<Method>(vinst, {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,8 +39,6 @@ TEST_CASE("meta/meta_utilities/arg6") {
|
|||||||
.function_("func_with_method", &func_with_method);
|
.function_("func_with_method", &func_with_method);
|
||||||
|
|
||||||
SUBCASE("int_member") {
|
SUBCASE("int_member") {
|
||||||
static_assert(sizeof(int_member_t) == 8);
|
|
||||||
|
|
||||||
const meta::function f = scope.get_function("func_with_member");
|
const meta::function f = scope.get_function("func_with_member");
|
||||||
REQUIRE(f);
|
REQUIRE(f);
|
||||||
|
|
||||||
@@ -55,8 +53,6 @@ TEST_CASE("meta/meta_utilities/arg6") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("int_method") {
|
SUBCASE("int_method") {
|
||||||
static_assert(sizeof(int_method_t) == 16);
|
|
||||||
|
|
||||||
const meta::function f = scope.get_function("func_with_method");
|
const meta::function f = scope.get_function("func_with_method");
|
||||||
REQUIRE(f);
|
REQUIRE(f);
|
||||||
|
|
||||||
|
|||||||
85
untests/meta_utilities/invoke_tests.cpp
Normal file
85
untests/meta_utilities/invoke_tests.cpp
Normal file
@@ -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_<clazz>()
|
||||||
|
.member_("member", &clazz::member)
|
||||||
|
.method_("method", &clazz::method)
|
||||||
|
.function_("function", &clazz::function);
|
||||||
|
|
||||||
|
const meta::class_type& clazz_type = meta::resolve_type<clazz>();
|
||||||
|
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<int>(clazz_function));
|
||||||
|
|
||||||
|
using function_t = decltype(&clazz::function);
|
||||||
|
CHECK(meta::is_invocable_with<function_t>(3));
|
||||||
|
CHECK(meta::is_invocable_with<function_t>(meta::value(3)));
|
||||||
|
CHECK(meta::is_invocable_with<function_t, int>());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
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<const clazz&>(clazz_member));
|
||||||
|
|
||||||
|
using member_t = decltype(&clazz::member);
|
||||||
|
CHECK(meta::is_invocable_with<member_t>(cl));
|
||||||
|
CHECK(meta::is_invocable_with<member_t>(meta::value{cl}));
|
||||||
|
CHECK(meta::is_invocable_with<member_t, const clazz&>());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
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<const clazz&, int>(clazz_method));
|
||||||
|
|
||||||
|
using method_t = decltype(&clazz::method);
|
||||||
|
CHECK(meta::is_invocable_with<method_t>(cl, 2));
|
||||||
|
CHECK(meta::is_invocable_with<method_t>(meta::value{cl}, meta::value(2)));
|
||||||
|
CHECK(meta::is_invocable_with<method_t, const clazz&, int>());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user