universal meta::invoke

This commit is contained in:
BlackMATov
2022-01-14 17:28:33 +07:00
parent 0a1303e215
commit ef5b04add0
13 changed files with 383 additions and 81 deletions

View File

@@ -54,3 +54,4 @@
#include "meta_utilities/arg.hpp"
#include "meta_utilities/inst.hpp"
#include "meta_utilities/value.hpp"
#include "meta_utilities/vinvoke.hpp"

View File

@@ -260,8 +260,8 @@ namespace meta_hpp
namespace meta_hpp::detail
{
struct ctor_state final {
using invoke_impl = std::function<value(std::span<arg>)>;
using is_invocable_with_impl = std::function<bool(std::span<arg_base>)>;
using invoke_impl = std::function<value(std::span<const arg>)>;
using is_invocable_with_impl = std::function<bool(std::span<const arg_base>)>;
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::optional<value>(std::span<arg>)>;
using is_invocable_with_impl = std::function<bool(std::span<arg_base>)>;
using invoke_impl = std::function<std::optional<value>(std::span<const arg>)>;
using is_invocable_with_impl = std::function<bool(std::span<const arg_base>)>;
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<std::optional<value>(const inst&, std::span<arg>)>;
using is_invocable_with_impl = std::function<bool(const inst_base&, std::span<arg_base>)>;
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<const arg_base>)>;
const method_index index;
const invoke_impl invoke;

View File

@@ -14,7 +14,7 @@
namespace meta_hpp::detail
{
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 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<arg_base> args) {
bool vargs_is_invocable_with(std::span<const arg_base> args) {
using ct = ctor_traits<Class, Args...>;
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<Class, Args...>, _1);
return std::bind(&vargs_invoke<Class, Args...>, _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<Class, Args...>, _1);
return std::bind(&vargs_is_invocable_with<Class, Args...>, _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<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);
} 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<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);
} 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<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);
} else {
return state_->is_invocable_with({});

View File

@@ -14,7 +14,7 @@
namespace meta_hpp::detail
{
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 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::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>>()) ) {
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<arg_base> args) {
bool vargs_is_invocable_with(std::span<const arg_base> args) {
using ft = function_traits<Function>;
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>, function, _1);
return std::bind(&vargs_invoke<Function>, 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<Function>, _1);
return std::bind(&vargs_is_invocable_with<Function>, _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<Function>()} {}
template < function_kind Function >
@@ -116,9 +116,9 @@ namespace meta_hpp
template < typename... Args >
std::optional<value> function::invoke(Args&&... args) const {
using namespace detail;
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);
} 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<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);
} 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<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);
} else {
return state_->is_invocable_with({});

View File

@@ -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<Member>;
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<qualified_type>())};
value_type return_value{std::invoke(std::move(member), inst.cast<qualified_type>())};
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 >
void raw_member_setter([[maybe_unused]] Member member, const inst& inst, const arg& arg) {
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");
}
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 >
bool raw_member_is_settable_with(const inst_base& inst, const arg_base& arg) {
using mt = member_traits<Member>;
@@ -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>, 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);
return std::bind(&vargs_invoke<Member>, 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<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 >
@@ -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<Member>()}
, is_settable_with{make_member_is_settable_with<Member>()} {}
@@ -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>(instance)});
const inst vinst{std::forward<Instance>(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>(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 >
@@ -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<Instance>{}});
const inst_base vinst{type_list<Instance>{}};
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>(instance)});
const inst_base vinst{std::forward<Instance>(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<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 >
[[nodiscard]] bool member::is_settable_with(Instance&& instance, Value&& value) const noexcept {
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);
}
}

View File

@@ -14,7 +14,7 @@
namespace meta_hpp::detail
{
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 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::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>>()) ) {
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<arg_base> args) {
bool vargs_is_invocable_with(const inst_base& inst, std::span<const arg_base> args) {
using mt = method_traits<Method>;
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>, method, _1, _2);
return std::bind(&vargs_invoke<Method>, 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<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 >
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<Method>()} {}
template < method_kind Method >
@@ -129,11 +129,12 @@ namespace meta_hpp
template < typename Instance, typename... Args >
std::optional<value> method::invoke(Instance&& instance, Args&&... args) const {
using namespace detail;
const inst vinst{std::forward<Instance>(instance)};
if constexpr ( sizeof...(Args) > 0 ) {
std::array<arg, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
return state_->invoke(inst{std::forward<Instance>(instance)}, vargs);
const std::array<arg, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
return state_->invoke(vinst, vargs);
} 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 >
bool method::is_invocable_with() const noexcept {
using namespace detail;
const inst_base vinst{type_list<Instance>{}};
if constexpr ( sizeof...(Args) > 0 ) {
std::array<arg_base, sizeof...(Args)> vargs{arg_base{type_list<Args>{}}...};
return state_->is_invocable_with(inst_base{type_list<Instance>{}}, vargs);
const std::array<arg_base, sizeof...(Args)> vargs{arg_base{type_list<Args>{}}...};
return state_->is_invocable_with(vinst, vargs);
} else {
return state_->is_invocable_with(inst_base{type_list<Instance>{}}, {});
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>(instance)};
if constexpr ( sizeof...(Args) > 0 ) {
std::array<arg_base, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
return state_->is_invocable_with(inst{std::forward<Instance>(instance)}, vargs);
const std::array<arg_base, sizeof...(Args)> vargs{arg_base{std::forward<Args>(args)}...};
return state_->is_invocable_with(vinst, vargs);
} else {
return state_->is_invocable_with(inst{std::forward<Instance>(instance)}, {});
return state_->is_invocable_with(vinst, {});
}
}
}

View File

@@ -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>(value)});
const arg vvalue{std::forward<Value>(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<Value>{}});
const arg_base vvalue{type_list<Value>{}};
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>(value)});
const arg vvalue{std::forward<Value>(value)};
return state_->is_settable_with(vvalue);
}
}

View File

@@ -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<T>
explicit arg_base(type_list<T>);
@@ -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<T>);

View File

@@ -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<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 >
requires decay_non_uvalue_kind<T>
// 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<T&&>{}}
: arg_base{std::forward<T>(v)}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
, data_{const_cast<std::remove_cvref_t<T>*>(std::addressof(v))} {}

View File

@@ -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<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 >
// NOLINTNEXTLINE(readability-named-parameter)
inst_base::inst_base(type_list<T>)
@@ -174,7 +184,7 @@ namespace meta_hpp::detail
template < decay_non_uvalue_kind T >
inst::inst(T&& v)
: inst_base{type_list<T&&>{}}
: inst_base{std::forward<T>(v)}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
, data_{const_cast<std::remove_cvref_t<T>*>(std::addressof(v))} {}

View 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, {});
}
}
}

View File

@@ -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);

View 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>());
}
}