mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-15 11:52:08 +07:00
invoke functions, methods and ctors with static arguments
This commit is contained in:
@@ -88,6 +88,7 @@ namespace meta_hpp
|
||||
namespace meta_hpp
|
||||
{
|
||||
class arg;
|
||||
class inst;
|
||||
class value;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,12 @@ namespace meta_hpp
|
||||
explicit operator bool() const noexcept;
|
||||
|
||||
const ctor_type& type() const noexcept;
|
||||
|
||||
template < typename... Args >
|
||||
value invoke(Args&&... args) const;
|
||||
|
||||
template < typename... Args >
|
||||
bool is_invocable_with() const noexcept;
|
||||
public:
|
||||
template < typename F >
|
||||
void visit(F&& f) const;
|
||||
@@ -39,11 +45,94 @@ namespace meta_hpp
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
using ctor_invoke = std::function<value(const arg*, std::size_t)>;
|
||||
|
||||
template < typename Class, typename... Args, std::size_t... Is >
|
||||
value raw_ctor_invoke_impl(
|
||||
const arg* args,
|
||||
std::index_sequence<Is...>)
|
||||
{
|
||||
using ct = ctor_traits<Class, Args...>;
|
||||
using class_type = typename ct::class_type;
|
||||
using argument_types = typename ct::argument_types;
|
||||
|
||||
if ( !(... && (args + Is)->can_cast_to<std::tuple_element_t<Is, argument_types>>()) ) {
|
||||
throw std::logic_error("an attempt to call a ctor with an incorrect argument types");
|
||||
}
|
||||
|
||||
class_type class_value{(args + Is)->cast<std::tuple_element_t<Is, argument_types>>()...};
|
||||
return value{std::forward<class_type>(class_value)};
|
||||
}
|
||||
|
||||
template < typename Class, typename... Args >
|
||||
value raw_ctor_invoke(
|
||||
const arg* args,
|
||||
std::size_t arg_count)
|
||||
{
|
||||
using ct = ctor_traits<Class, Args...>;
|
||||
|
||||
if ( arg_count != ct::arity ) {
|
||||
throw std::logic_error("an attempt to call a ctor with an incorrect arity");
|
||||
}
|
||||
|
||||
return raw_ctor_invoke_impl<Class, Args...>(
|
||||
args,
|
||||
std::make_index_sequence<ct::arity>());
|
||||
}
|
||||
|
||||
template < typename Class, typename... Args >
|
||||
ctor_invoke make_ctor_invoke() {
|
||||
using namespace std::placeholders;
|
||||
return std::bind(&raw_ctor_invoke<Class, Args...>, _1, _2);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
using ctor_is_invocable_with = std::function<bool(const arg_base*, std::size_t)>;
|
||||
|
||||
template < typename Class, typename... Args, std::size_t... Is >
|
||||
bool raw_ctor_is_invocable_with_impl(
|
||||
const arg_base* arg_bases,
|
||||
std::index_sequence<Is...>)
|
||||
{
|
||||
using ct = ctor_traits<Class, Args...>;
|
||||
using argument_types = typename ct::argument_types;
|
||||
return (... && (arg_bases + Is)->can_cast_to<std::tuple_element_t<Is, argument_types>>() );
|
||||
}
|
||||
|
||||
template < typename Class, typename... Args >
|
||||
bool raw_ctor_is_invocable_with(
|
||||
const arg_base* arg_bases,
|
||||
std::size_t arg_count)
|
||||
{
|
||||
using ct = ctor_traits<Class, Args...>;
|
||||
|
||||
if ( arg_count != ct::arity ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return raw_ctor_is_invocable_with_impl<Class, Args...>(
|
||||
arg_bases,
|
||||
std::make_index_sequence<ct::arity>());
|
||||
}
|
||||
|
||||
template < typename Class, typename... Args >
|
||||
ctor_is_invocable_with make_ctor_is_invocable_with() {
|
||||
using namespace std::placeholders;
|
||||
return std::bind(&raw_ctor_is_invocable_with<Class, Args...>, _1, _2);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
struct ctor_info::state final {
|
||||
ctor_type type;
|
||||
data_info_map datas;
|
||||
detail::ctor_invoke invoke;
|
||||
detail::ctor_is_invocable_with is_invocable_with;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -61,6 +150,18 @@ namespace meta_hpp
|
||||
inline const ctor_type& ctor_info::type() const noexcept {
|
||||
return state_->type;
|
||||
}
|
||||
|
||||
template < typename... Args >
|
||||
value ctor_info::invoke(Args&&... args) const {
|
||||
std::array<arg, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
|
||||
return state_->invoke(vargs.data(), vargs.size());
|
||||
}
|
||||
|
||||
template < typename... Args >
|
||||
bool ctor_info::is_invocable_with() const noexcept {
|
||||
std::array<arg_base, sizeof...(Args)> arg_bases{arg_base{typename_arg<Args>}...};
|
||||
return state_->is_invocable_with(arg_bases.data(), arg_bases.size());
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
@@ -88,6 +189,8 @@ namespace meta_hpp
|
||||
ctor_info::ctor_info(typename_arg_t<Class>, typename_arg_t<Args...>)
|
||||
: state_{std::make_shared<state>(state{
|
||||
ctor_type{typename_arg<Class>, typename_arg<Args...>},
|
||||
{}
|
||||
{},
|
||||
detail::make_ctor_invoke<Class, Args...>(),
|
||||
detail::make_ctor_is_invocable_with<Class, Args...>(),
|
||||
})} {}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,12 @@ namespace meta_hpp
|
||||
|
||||
const std::string& name() const noexcept;
|
||||
const function_type& type() const noexcept;
|
||||
|
||||
template < typename... Args >
|
||||
std::optional<value> invoke(Args&&... args) const;
|
||||
|
||||
template < typename... Args >
|
||||
bool is_invocable_with() const noexcept;
|
||||
public:
|
||||
template < typename F >
|
||||
void visit(F&& f) const;
|
||||
@@ -33,19 +39,112 @@ namespace meta_hpp
|
||||
template < typename Function > friend class function_;
|
||||
|
||||
template < typename Function >
|
||||
explicit function_info(std::string name, Function instance);
|
||||
explicit function_info(std::string name, Function function);
|
||||
private:
|
||||
struct state;
|
||||
std::shared_ptr<state> state_;
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
using function_invoke = std::function<std::optional<value>(const arg*, std::size_t)>;
|
||||
|
||||
template < typename Function, std::size_t... Is >
|
||||
std::optional<value> raw_function_invoke_impl(
|
||||
Function function,
|
||||
const arg* args,
|
||||
std::index_sequence<Is...>)
|
||||
{
|
||||
using ft = function_pointer_traits<Function>;
|
||||
using return_type = typename ft::return_type;
|
||||
using argument_types = typename ft::argument_types;
|
||||
|
||||
if ( !(... && (args + Is)->can_cast_to<std::tuple_element_t<Is, argument_types>>()) ) {
|
||||
throw std::logic_error("an attempt to call a function with an incorrect argument types");
|
||||
}
|
||||
|
||||
if constexpr ( std::is_void_v<return_type> ) {
|
||||
std::invoke(function,
|
||||
(args + Is)->cast<std::tuple_element_t<Is, argument_types>>()...);
|
||||
return std::nullopt;
|
||||
} else {
|
||||
return_type return_value{std::invoke(function,
|
||||
(args + Is)->cast<std::tuple_element_t<Is, argument_types>>()...)};
|
||||
return value{std::forward<return_type>(return_value)};
|
||||
}
|
||||
}
|
||||
|
||||
template < typename Function >
|
||||
std::optional<value> raw_function_invoke(
|
||||
Function function,
|
||||
const arg* args,
|
||||
std::size_t arg_count)
|
||||
{
|
||||
using ft = function_pointer_traits<Function>;
|
||||
|
||||
if ( arg_count != ft::arity ) {
|
||||
throw std::logic_error("an attempt to call a function with an incorrect arity");
|
||||
}
|
||||
|
||||
return raw_function_invoke_impl<Function>(
|
||||
function,
|
||||
args,
|
||||
std::make_index_sequence<ft::arity>());
|
||||
}
|
||||
|
||||
template < typename Function >
|
||||
function_invoke make_function_invoke(Function function) {
|
||||
using namespace std::placeholders;
|
||||
return std::bind(&raw_function_invoke<Function>, function, _1, _2);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
using function_is_invocable_with = std::function<bool(const arg_base*, std::size_t)>;
|
||||
|
||||
template < typename Function, std::size_t... Is >
|
||||
bool raw_function_is_invocable_with_impl(
|
||||
const arg_base* arg_bases,
|
||||
std::index_sequence<Is...>)
|
||||
{
|
||||
using ft = function_pointer_traits<Function>;
|
||||
using argument_types = typename ft::argument_types;
|
||||
return (... && (arg_bases + Is)->can_cast_to<std::tuple_element_t<Is, argument_types>>() );
|
||||
}
|
||||
|
||||
template < typename Function >
|
||||
bool raw_function_is_invocable_with(
|
||||
const arg_base* arg_bases,
|
||||
std::size_t arg_count)
|
||||
{
|
||||
using ft = function_pointer_traits<Function>;
|
||||
|
||||
if ( arg_count != ft::arity ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return raw_function_is_invocable_with_impl<Function>(
|
||||
arg_bases,
|
||||
std::make_index_sequence<ft::arity>());
|
||||
}
|
||||
|
||||
template < typename Function >
|
||||
function_is_invocable_with make_function_is_invocable_with() {
|
||||
using namespace std::placeholders;
|
||||
return std::bind(&raw_function_is_invocable_with<Function>, _1, _2);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
struct function_info::state final {
|
||||
std::string name;
|
||||
function_type type;
|
||||
data_info_map datas;
|
||||
detail::function_invoke invoke;
|
||||
detail::function_is_invocable_with is_invocable_with;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -67,6 +166,18 @@ namespace meta_hpp
|
||||
inline const function_type& function_info::type() const noexcept {
|
||||
return state_->type;
|
||||
}
|
||||
|
||||
template < typename... Args >
|
||||
std::optional<value> function_info::invoke(Args&&... args) const {
|
||||
std::array<arg, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
|
||||
return state_->invoke(vargs.data(), vargs.size());
|
||||
}
|
||||
|
||||
template < typename... Args >
|
||||
bool function_info::is_invocable_with() const noexcept {
|
||||
std::array<arg_base, sizeof...(Args)> arg_bases{arg_base{typename_arg<Args>}...};
|
||||
return state_->is_invocable_with(arg_bases.data(), arg_bases.size());
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
@@ -91,12 +202,12 @@ namespace meta_hpp
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < typename Function >
|
||||
function_info::function_info(std::string name, Function instance)
|
||||
function_info::function_info(std::string name, Function function)
|
||||
: state_{std::make_shared<state>(state{
|
||||
std::move(name),
|
||||
type_db::get<Function>().template as<function_type>(),
|
||||
{}
|
||||
})} {
|
||||
(void)instance;
|
||||
}
|
||||
{},
|
||||
detail::make_function_invoke<Function>(function),
|
||||
detail::make_function_is_invocable_with<Function>(),
|
||||
})} {}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,12 @@ namespace meta_hpp
|
||||
|
||||
const std::string& name() const noexcept;
|
||||
const method_type& type() const noexcept;
|
||||
|
||||
template < typename Instance, typename... Args >
|
||||
std::optional<value> invoke(Instance&& instance, Args&&... args) const;
|
||||
|
||||
template < typename Inst, typename... Args >
|
||||
bool is_invocable_with() const noexcept;
|
||||
public:
|
||||
template < typename F >
|
||||
void visit(F&& f) const;
|
||||
@@ -33,19 +39,128 @@ namespace meta_hpp
|
||||
template < typename Method > friend class method_;
|
||||
|
||||
template < typename Method >
|
||||
explicit method_info(std::string name, Method instance);
|
||||
explicit method_info(std::string name, Method method);
|
||||
private:
|
||||
struct state;
|
||||
std::shared_ptr<state> state_;
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
using method_invoke = std::function<std::optional<value>(const inst&, const arg*, std::size_t)>;
|
||||
|
||||
template < typename Method, std::size_t... Is >
|
||||
std::optional<value> raw_method_invoke_impl(
|
||||
Method method,
|
||||
const inst& inst,
|
||||
const arg* args,
|
||||
std::index_sequence<Is...>)
|
||||
{
|
||||
using mt = method_pointer_traits<Method>;
|
||||
using return_type = typename mt::return_type;
|
||||
using qualified_type = typename mt::qualified_type;
|
||||
using argument_types = typename mt::argument_types;
|
||||
|
||||
if ( !inst.can_cast_to<qualified_type>() ) {
|
||||
throw std::logic_error("an attempt to call a method with an incorrect instance type");
|
||||
}
|
||||
|
||||
if ( !(... && (args + Is)->can_cast_to<std::tuple_element_t<Is, argument_types>>()) ) {
|
||||
throw std::logic_error("an attempt to call a method with an incorrect argument types");
|
||||
}
|
||||
|
||||
if constexpr ( std::is_void_v<return_type> ) {
|
||||
std::invoke(method,
|
||||
inst.cast<qualified_type>(),
|
||||
(args + Is)->cast<std::tuple_element_t<Is, argument_types>>()...);
|
||||
return std::nullopt;
|
||||
} else {
|
||||
return_type return_value{std::invoke(method,
|
||||
inst.cast<qualified_type>(),
|
||||
(args + Is)->cast<std::tuple_element_t<Is, argument_types>>()...)};
|
||||
return value{std::forward<return_type>(return_value)};
|
||||
}
|
||||
}
|
||||
|
||||
template < typename Method >
|
||||
std::optional<value> raw_method_invoke(
|
||||
Method method,
|
||||
const inst& inst,
|
||||
const arg* args,
|
||||
std::size_t arg_count)
|
||||
{
|
||||
using mt = method_pointer_traits<Method>;
|
||||
|
||||
if ( arg_count != mt::arity ) {
|
||||
throw std::logic_error("an attempt to call a method with an incorrect arity");
|
||||
}
|
||||
|
||||
return raw_method_invoke_impl<Method>(
|
||||
method,
|
||||
inst,
|
||||
args,
|
||||
std::make_index_sequence<mt::arity>());
|
||||
}
|
||||
|
||||
template < typename Method >
|
||||
method_invoke make_method_invoke(Method method) {
|
||||
using namespace std::placeholders;
|
||||
return std::bind(&raw_method_invoke<Method>, method, _1, _2, _3);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
using method_is_invocable_with = std::function<bool(const inst_base&, const arg_base*, std::size_t)>;
|
||||
|
||||
template < typename Method, std::size_t... Is >
|
||||
bool raw_method_is_invocable_with_impl(
|
||||
const inst_base& inst_base,
|
||||
const arg_base* arg_bases,
|
||||
std::index_sequence<Is...>)
|
||||
{
|
||||
using mt = method_pointer_traits<Method>;
|
||||
using qualified_type = typename mt::qualified_type;
|
||||
using argument_types = typename mt::argument_types;
|
||||
|
||||
return inst_base.can_cast_to<qualified_type>()
|
||||
&& (... && (arg_bases + Is)->can_cast_to<std::tuple_element_t<Is, argument_types>>() );
|
||||
}
|
||||
|
||||
template < typename Method >
|
||||
bool raw_method_is_invocable_with(
|
||||
const inst_base& inst_base,
|
||||
const arg_base* arg_bases,
|
||||
std::size_t arg_count)
|
||||
{
|
||||
using mt = method_pointer_traits<Method>;
|
||||
|
||||
if ( arg_count != mt::arity ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return raw_method_is_invocable_with_impl<Method>(
|
||||
inst_base,
|
||||
arg_bases,
|
||||
std::make_index_sequence<mt::arity>());
|
||||
}
|
||||
|
||||
template < typename Method >
|
||||
method_is_invocable_with make_method_is_invocable_with() {
|
||||
using namespace std::placeholders;
|
||||
return std::bind(&raw_method_is_invocable_with<Method>, _1, _2, _3);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
struct method_info::state final {
|
||||
std::string name;
|
||||
method_type type;
|
||||
data_info_map datas;
|
||||
detail::method_invoke invoke;
|
||||
detail::method_is_invocable_with is_invocable_with;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -67,6 +182,18 @@ namespace meta_hpp
|
||||
inline const method_type& method_info::type() const noexcept {
|
||||
return state_->type;
|
||||
}
|
||||
|
||||
template < typename Instance, typename... Args >
|
||||
std::optional<value> method_info::invoke(Instance&& instance, Args&&... args) const {
|
||||
std::array<arg, sizeof...(Args)> vargs{arg{std::forward<Args>(args)}...};
|
||||
return state_->invoke(inst{std::forward<Instance>(instance)}, vargs.data(), vargs.size());
|
||||
}
|
||||
|
||||
template < typename Inst, typename... Args >
|
||||
bool method_info::is_invocable_with() const noexcept {
|
||||
std::array<arg_base, sizeof...(Args)> arg_bases{arg_base{typename_arg<Args>}...};
|
||||
return state_->is_invocable_with(inst_base{typename_arg<Inst>}, arg_bases.data(), arg_bases.size());
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
@@ -91,12 +218,12 @@ namespace meta_hpp
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < typename Method >
|
||||
method_info::method_info(std::string name, Method instance)
|
||||
method_info::method_info(std::string name, Method method)
|
||||
: state_{std::make_shared<state>(state{
|
||||
std::move(name),
|
||||
type_db::get<Method>().template as<method_type>(),
|
||||
{}
|
||||
})} {
|
||||
(void)instance;
|
||||
}
|
||||
{},
|
||||
detail::make_method_invoke<Method>(method),
|
||||
detail::make_method_is_invocable_with<Method>(),
|
||||
})} {}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,9 @@ namespace meta_hpp
|
||||
enum class method_flags : unsigned {
|
||||
is_const = 1 << 0,
|
||||
is_noexcept = 1 << 1,
|
||||
is_volatile = 1 << 2,
|
||||
is_lvalue_qualified = 1 << 3,
|
||||
is_rvalue_qualified = 1 << 4,
|
||||
};
|
||||
|
||||
ENUM_HPP_OPERATORS_DECL(method_flags)
|
||||
@@ -39,6 +42,9 @@ namespace meta_hpp
|
||||
bitflags<method_flags> flags() const noexcept;
|
||||
bool is_const() const noexcept;
|
||||
bool is_noexcept() const noexcept;
|
||||
bool is_volatile() const noexcept;
|
||||
bool is_lvalue_qualified() const noexcept;
|
||||
bool is_rvalue_qualified() const noexcept;
|
||||
private:
|
||||
struct state;
|
||||
std::shared_ptr<state> state_;
|
||||
@@ -56,6 +62,7 @@ namespace meta_hpp::detail
|
||||
|
||||
using class_type = C;
|
||||
using return_type = R;
|
||||
using qualified_type = C;
|
||||
using argument_types = std::tuple<Args...>;
|
||||
|
||||
static any_type make_class_type() {
|
||||
@@ -77,6 +84,7 @@ namespace meta_hpp::detail
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) const> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = const C;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_const;
|
||||
}
|
||||
@@ -84,6 +92,7 @@ namespace meta_hpp::detail
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) noexcept> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = C;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_noexcept;
|
||||
}
|
||||
@@ -91,10 +100,173 @@ namespace meta_hpp::detail
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) const noexcept> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = const C;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_const | method_flags::is_noexcept;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) &> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = C&;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_lvalue_qualified;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) & noexcept> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = C&;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_noexcept | method_flags::is_lvalue_qualified;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) const &> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = const C&;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_const | method_flags::is_lvalue_qualified;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) const & noexcept> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = const C&;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_const | method_flags::is_noexcept | method_flags::is_lvalue_qualified;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) &&> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = C&&;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_rvalue_qualified;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) && noexcept> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = C&&;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_noexcept | method_flags::is_rvalue_qualified;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) const &&> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = const C&&;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_const | method_flags::is_rvalue_qualified;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) const && noexcept> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = const C&&;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_const | method_flags::is_noexcept | method_flags::is_rvalue_qualified;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) volatile> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = C;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_volatile;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) volatile const> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = const C;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_volatile | method_flags::is_const;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) volatile noexcept> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = C;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_volatile | method_flags::is_noexcept;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) volatile const noexcept> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = const C;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_volatile | method_flags::is_const | method_flags::is_noexcept;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) volatile &> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = C&;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_volatile | method_flags::is_lvalue_qualified;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) volatile & noexcept> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = C&;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_volatile | method_flags::is_noexcept | method_flags::is_lvalue_qualified;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) volatile const &> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = const C&;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_volatile | method_flags::is_const | method_flags::is_lvalue_qualified;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) volatile const & noexcept> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = const C&;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_volatile | method_flags::is_const | method_flags::is_noexcept | method_flags::is_lvalue_qualified;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) volatile &&> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = C&&;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_volatile | method_flags::is_rvalue_qualified;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) volatile && noexcept> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = C&&;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_volatile | method_flags::is_noexcept | method_flags::is_rvalue_qualified;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) volatile const &&> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = const C&&;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_volatile | method_flags::is_const | method_flags::is_rvalue_qualified;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename R, typename C, typename... Args >
|
||||
struct method_pointer_traits<R(C::*)(Args...) volatile const && noexcept> : method_pointer_traits<R(C::*)(Args...)> {
|
||||
using qualified_type = const C&&;
|
||||
static bitflags<method_flags> make_flags() noexcept {
|
||||
return method_flags::is_volatile | method_flags::is_const | method_flags::is_noexcept | method_flags::is_rvalue_qualified;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
@@ -153,4 +325,16 @@ namespace meta_hpp
|
||||
inline bool method_type::is_noexcept() const noexcept {
|
||||
return state_->flags.has(method_flags::is_noexcept);
|
||||
}
|
||||
|
||||
inline bool method_type::is_volatile() const noexcept {
|
||||
return state_->flags.has(method_flags::is_volatile);
|
||||
}
|
||||
|
||||
inline bool method_type::is_lvalue_qualified() const noexcept {
|
||||
return state_->flags.has(method_flags::is_lvalue_qualified);
|
||||
}
|
||||
|
||||
inline bool method_type::is_rvalue_qualified() const noexcept {
|
||||
return state_->flags.has(method_flags::is_rvalue_qualified);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,4 +9,5 @@
|
||||
#include "meta_fwd.hpp"
|
||||
|
||||
#include "meta_utilities/arg.hpp"
|
||||
#include "meta_utilities/inst.hpp"
|
||||
#include "meta_utilities/value.hpp"
|
||||
|
||||
183
headers/meta.hpp/meta_utilities/inst.hpp
Normal file
183
headers/meta.hpp/meta_utilities/inst.hpp
Normal file
@@ -0,0 +1,183 @@
|
||||
/*******************************************************************************
|
||||
* 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_fwd.hpp"
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
class inst_base {
|
||||
public:
|
||||
enum class ref_types {
|
||||
ref,
|
||||
rref,
|
||||
cref,
|
||||
crref,
|
||||
};
|
||||
public:
|
||||
inst_base() = delete;
|
||||
|
||||
inst_base(inst_base&&) = delete;
|
||||
inst_base& operator=(inst_base&&) = delete;
|
||||
|
||||
inst_base(const inst_base&) = delete;
|
||||
inst_base& operator=(const inst_base&) = delete;
|
||||
|
||||
template < typename T, std::enable_if_t<
|
||||
std::is_lvalue_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>
|
||||
, int> = 0>
|
||||
explicit inst_base(typename_arg_t<T>);
|
||||
|
||||
template < typename T, std::enable_if_t<
|
||||
std::is_class_v<T> ||
|
||||
(std::is_rvalue_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>)
|
||||
, int> = 0>
|
||||
explicit inst_base(typename_arg_t<T>);
|
||||
|
||||
bool is_const() const noexcept;
|
||||
bool is_lvalue() const noexcept;
|
||||
bool is_rvalue() const noexcept;
|
||||
|
||||
any_type raw_type() const noexcept;
|
||||
ref_types ref_type() const noexcept;
|
||||
|
||||
template < typename To >
|
||||
bool can_cast_to() const noexcept;
|
||||
private:
|
||||
any_type raw_type_{};
|
||||
ref_types ref_type_{};
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < typename T, std::enable_if_t<
|
||||
std::is_lvalue_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>
|
||||
, int> >
|
||||
inst_base::inst_base(typename_arg_t<T>)
|
||||
: raw_type_{type_db::get<stdex::remove_cvref_t<T>>()}
|
||||
, ref_type_{std::is_const_v<std::remove_reference_t<T>> ? ref_types::cref : ref_types::ref} {}
|
||||
|
||||
template < typename T, std::enable_if_t<
|
||||
std::is_class_v<T> ||
|
||||
(std::is_rvalue_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>)
|
||||
, int> >
|
||||
inst_base::inst_base(typename_arg_t<T>)
|
||||
: raw_type_{type_db::get<stdex::remove_cvref_t<T>>()}
|
||||
, ref_type_{std::is_const_v<std::remove_reference_t<T>> ? ref_types::crref : ref_types::rref} {}
|
||||
|
||||
inline bool inst_base::is_const() const noexcept {
|
||||
return ref_type_ == ref_types::cref
|
||||
|| ref_type_ == ref_types::crref;
|
||||
}
|
||||
|
||||
inline bool inst_base::is_lvalue() const noexcept {
|
||||
return ref_type_ == ref_types::ref
|
||||
|| ref_type_ == ref_types::cref;
|
||||
}
|
||||
|
||||
inline bool inst_base::is_rvalue() const noexcept {
|
||||
return ref_type_ == ref_types::rref
|
||||
|| ref_type_ == ref_types::crref;
|
||||
}
|
||||
|
||||
inline any_type inst_base::raw_type() const noexcept {
|
||||
return raw_type_;
|
||||
}
|
||||
|
||||
inline inst_base::ref_types inst_base::ref_type() const noexcept {
|
||||
return ref_type_;
|
||||
}
|
||||
|
||||
template < typename To >
|
||||
bool inst_base::can_cast_to() const noexcept {
|
||||
static_assert(
|
||||
std::is_class_v<To> ||
|
||||
(std::is_reference_v<To> && std::is_class_v<std::remove_reference_t<To>>));
|
||||
|
||||
constexpr bool to_const = std::is_const_v<std::remove_reference_t<To>>;
|
||||
|
||||
if ( !to_const && is_const() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if constexpr ( std::is_lvalue_reference_v<To> ) {
|
||||
if ( !is_lvalue() ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr ( std::is_rvalue_reference_v<To> ) {
|
||||
if ( !is_rvalue() ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
using to_raw_type = stdex::remove_cvref_t<To>;
|
||||
return raw_type() == type_db::get<to_raw_type>();
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
class inst final : public inst_base {
|
||||
public:
|
||||
inst() = delete;
|
||||
|
||||
inst(inst&&) = delete;
|
||||
inst& operator=(inst&&) = delete;
|
||||
|
||||
inst(const inst&) = delete;
|
||||
inst& operator=(const inst&) = delete;
|
||||
|
||||
template < typename T, std::enable_if_t<
|
||||
std::is_class_v<T> ||
|
||||
(std::is_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>)
|
||||
, int> = 0 >
|
||||
explicit inst(T&& v);
|
||||
|
||||
template < typename To >
|
||||
decltype(auto) cast() const;
|
||||
private:
|
||||
void* data_{};
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < typename T, std::enable_if_t<
|
||||
std::is_class_v<T> ||
|
||||
(std::is_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>)
|
||||
, int> >
|
||||
inst::inst(T&& v)
|
||||
: inst_base{typename_arg<T&&>}
|
||||
, data_{const_cast<stdex::remove_cvref_t<T>*>(std::addressof(v))} {}
|
||||
|
||||
template < typename To >
|
||||
decltype(auto) inst::cast() const {
|
||||
if ( !can_cast_to<To>() ) {
|
||||
throw std::logic_error("bad inst cast");
|
||||
}
|
||||
|
||||
if constexpr ( std::is_reference_v<To> ) {
|
||||
using raw_type_with_cv = std::remove_reference_t<To>;
|
||||
|
||||
if constexpr ( std::is_lvalue_reference_v<To> ) {
|
||||
return *static_cast<raw_type_with_cv*>(data_);
|
||||
}
|
||||
|
||||
if constexpr ( std::is_rvalue_reference_v<To> ) {
|
||||
return std::move(*static_cast<raw_type_with_cv*>(data_));
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr ( !std::is_reference_v<To>) {
|
||||
using raw_type_with_cv = To;
|
||||
return *static_cast<raw_type_with_cv*>(data_);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ namespace
|
||||
|
||||
class derived final : public base {
|
||||
public:
|
||||
derived() = default;
|
||||
};
|
||||
|
||||
struct empty final {};
|
||||
|
||||
@@ -23,6 +23,10 @@ namespace
|
||||
[[maybe_unused]] explicit ivec2(int v): x{v}, y{v} {}
|
||||
[[maybe_unused]] ivec2(int x, int y): x{x}, y{y} {}
|
||||
};
|
||||
|
||||
[[maybe_unused]] bool operator==(const ivec2& l, const ivec2& r) noexcept {
|
||||
return l.x == r.x && l.y == r.y;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("features/infos/ctor") {
|
||||
@@ -57,6 +61,22 @@ TEST_CASE("features/infos/ctor") {
|
||||
CHECK(ci.type().id() == ci2.type().id());
|
||||
CHECK(ci.type().id() == ci2.type().id());
|
||||
}
|
||||
|
||||
{
|
||||
CHECK(ci.is_invocable_with<>());
|
||||
|
||||
CHECK_FALSE(ci.is_invocable_with<int>());
|
||||
CHECK_FALSE(ci.is_invocable_with<const int>());
|
||||
CHECK_FALSE(ci.is_invocable_with<int&>());
|
||||
CHECK_FALSE(ci.is_invocable_with<const int&>());
|
||||
CHECK_FALSE(ci.is_invocable_with<int&&>());
|
||||
CHECK_FALSE(ci.is_invocable_with<const int&&>());
|
||||
}
|
||||
|
||||
{
|
||||
CHECK(ci.invoke().equals(ivec2{}));
|
||||
CHECK_THROWS(ci.invoke(42));
|
||||
}
|
||||
}
|
||||
|
||||
SUBCASE("int") {
|
||||
@@ -76,6 +96,22 @@ TEST_CASE("features/infos/ctor") {
|
||||
CHECK(ci.type().id() == ci2.type().id());
|
||||
CHECK(ci.type().id() == ci2.type().id());
|
||||
}
|
||||
|
||||
{
|
||||
CHECK_FALSE(ci.is_invocable_with<>());
|
||||
|
||||
CHECK(ci.is_invocable_with<int>());
|
||||
CHECK(ci.is_invocable_with<const int>());
|
||||
CHECK(ci.is_invocable_with<int&>());
|
||||
CHECK(ci.is_invocable_with<const int&>());
|
||||
CHECK(ci.is_invocable_with<int&&>());
|
||||
CHECK(ci.is_invocable_with<const int&&>());
|
||||
}
|
||||
|
||||
{
|
||||
CHECK_THROWS(ci.invoke());
|
||||
CHECK(ci.invoke(42).equals(ivec2{42}));
|
||||
}
|
||||
}
|
||||
|
||||
SUBCASE("const ivec2&") {
|
||||
@@ -95,6 +131,29 @@ TEST_CASE("features/infos/ctor") {
|
||||
CHECK(ci.type().id() == ci2.type().id());
|
||||
CHECK(ci.type().id() == ci2.type().id());
|
||||
}
|
||||
|
||||
{
|
||||
CHECK_FALSE(ci.is_invocable_with<>());
|
||||
|
||||
CHECK_FALSE(ci.is_invocable_with<int>());
|
||||
CHECK_FALSE(ci.is_invocable_with<const int>());
|
||||
CHECK_FALSE(ci.is_invocable_with<int&>());
|
||||
CHECK_FALSE(ci.is_invocable_with<const int&>());
|
||||
CHECK_FALSE(ci.is_invocable_with<int&&>());
|
||||
CHECK_FALSE(ci.is_invocable_with<const int&&>());
|
||||
|
||||
CHECK(ci.is_invocable_with<ivec2>());
|
||||
CHECK(ci.is_invocable_with<ivec2&>());
|
||||
CHECK(ci.is_invocable_with<const ivec2&>());
|
||||
CHECK(ci.is_invocable_with<ivec2&&>());
|
||||
CHECK(ci.is_invocable_with<const ivec2&&>());
|
||||
}
|
||||
|
||||
{
|
||||
CHECK_THROWS(ci.invoke());
|
||||
CHECK_THROWS(ci.invoke(42));
|
||||
CHECK(ci.invoke(ivec2{21,42}).equals(ivec2{21,42}));
|
||||
}
|
||||
}
|
||||
|
||||
SUBCASE("int,int") {
|
||||
@@ -116,5 +175,27 @@ TEST_CASE("features/infos/ctor") {
|
||||
CHECK(ci.type().id() == ci2.type().id());
|
||||
CHECK(ci.type().id() == ci2.type().id());
|
||||
}
|
||||
|
||||
{
|
||||
CHECK_FALSE(ci.is_invocable_with<>());
|
||||
|
||||
CHECK_FALSE(ci.is_invocable_with<int>());
|
||||
CHECK_FALSE(ci.is_invocable_with<const int>());
|
||||
CHECK_FALSE(ci.is_invocable_with<int&>());
|
||||
CHECK_FALSE(ci.is_invocable_with<const int&>());
|
||||
CHECK_FALSE(ci.is_invocable_with<int&&>());
|
||||
CHECK_FALSE(ci.is_invocable_with<const int&&>());
|
||||
|
||||
CHECK(ci.is_invocable_with<int, int>());
|
||||
CHECK(ci.is_invocable_with<int&, int&&>());
|
||||
CHECK(ci.is_invocable_with<const int&, const int&&>());
|
||||
}
|
||||
|
||||
{
|
||||
CHECK_THROWS(ci.invoke());
|
||||
CHECK_THROWS(ci.invoke(42));
|
||||
CHECK_THROWS(ci.invoke(ivec2{21,42}));
|
||||
CHECK(ci.invoke(21,42).equals(ivec2{21,42}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,88 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace meta_hpp;
|
||||
using namespace std::string_literals;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct ivec2 {
|
||||
int x{};
|
||||
int y{};
|
||||
|
||||
[[maybe_unused]] ivec2() = default;
|
||||
[[maybe_unused]] ivec2(const ivec2& other) = default;
|
||||
[[maybe_unused]] explicit ivec2(int v): x{v}, y{v} {}
|
||||
[[maybe_unused]] ivec2(int x, int y): x{x}, y{y} {}
|
||||
};
|
||||
|
||||
bool operator==(const ivec2& l, const ivec2& r) noexcept {
|
||||
return l.x == r.x && l.y == r.y;
|
||||
}
|
||||
|
||||
ivec2 iadd(const ivec2& l, const ivec2& r) noexcept {
|
||||
return {l.x + r.x, l.y + r.y};
|
||||
}
|
||||
|
||||
int ilength2(const ivec2& v) noexcept {
|
||||
return v.x * v.x + v.y * v.y;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("features/infos/function") {
|
||||
registry db;
|
||||
|
||||
db(
|
||||
namespace_{"vmath"}(
|
||||
class_<ivec2>{"ivec2"},
|
||||
function_{"iadd", &iadd}(data_{"info", "iadd function"s}),
|
||||
function_{"ilength2", &ilength2}(data_{"info", "ilength2 function"s})
|
||||
)
|
||||
);
|
||||
|
||||
SUBCASE("iadd") {
|
||||
const function_info fi = db.get_function_by_path("vmath::iadd");
|
||||
REQUIRE(fi);
|
||||
|
||||
REQUIRE(fi.get_data_by_name("info"));
|
||||
CHECK(fi.get_data_by_name("info").value().equals("iadd function"s));
|
||||
|
||||
CHECK_FALSE(fi.is_invocable_with());
|
||||
CHECK_FALSE(fi.is_invocable_with<int>());
|
||||
CHECK_FALSE(fi.is_invocable_with<ivec2, int>());
|
||||
CHECK_FALSE(fi.is_invocable_with<ivec2, ivec2, int>());
|
||||
|
||||
CHECK(fi.is_invocable_with<ivec2, ivec2>());
|
||||
CHECK(fi.is_invocable_with<ivec2&&, const ivec2&>());
|
||||
|
||||
CHECK_THROWS(fi.invoke());
|
||||
CHECK_THROWS(fi.invoke(42));
|
||||
CHECK_THROWS(fi.invoke(ivec2{}, 42));
|
||||
|
||||
CHECK(fi.invoke(ivec2{1,2},ivec2{3,4}));
|
||||
CHECK(fi.invoke(ivec2{1,2},ivec2{3,4})->equals(ivec2{4,6}));
|
||||
}
|
||||
|
||||
SUBCASE("ilength2") {
|
||||
const function_info fi = db.get_function_by_path("vmath::ilength2");
|
||||
REQUIRE(fi);
|
||||
|
||||
REQUIRE(fi.get_data_by_name("info"));
|
||||
CHECK(fi.get_data_by_name("info").value().equals("ilength2 function"s));
|
||||
|
||||
CHECK_FALSE(fi.is_invocable_with());
|
||||
CHECK_FALSE(fi.is_invocable_with<int>());
|
||||
CHECK_FALSE(fi.is_invocable_with<ivec2, int>());
|
||||
|
||||
CHECK(fi.is_invocable_with<ivec2>());
|
||||
CHECK(fi.is_invocable_with<const ivec2&>());
|
||||
|
||||
CHECK_THROWS(fi.invoke());
|
||||
CHECK_THROWS(fi.invoke(42));
|
||||
CHECK_THROWS(fi.invoke(ivec2{}, 42));
|
||||
|
||||
CHECK(fi.invoke(ivec2{2,3}));
|
||||
CHECK(fi.invoke(ivec2{2,3})->equals(13));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,779 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace meta_hpp;
|
||||
using namespace std::string_literals;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct clazz {
|
||||
clazz() = default;
|
||||
|
||||
clazz(clazz&&) = delete;
|
||||
clazz(const clazz&) = delete;
|
||||
|
||||
clazz& operator=(clazz&&) = delete;
|
||||
clazz& operator=(const clazz&) = delete;
|
||||
|
||||
//
|
||||
|
||||
int non_const_method() { return 1; }
|
||||
int non_const_method_noexcept() noexcept { return 2; }
|
||||
|
||||
int const_method() const { return 3; }
|
||||
int const_method_noexcept() const noexcept { return 4; }
|
||||
|
||||
int non_const_method_ref() & { return 5; }
|
||||
int non_const_method_noexcept_ref() & noexcept { return 6; }
|
||||
|
||||
int const_method_ref() const & { return 7; }
|
||||
int const_method_noexcept_ref() const & noexcept { return 8; }
|
||||
|
||||
int non_const_method_rref() && { return 9; }
|
||||
int non_const_method_noexcept_rref() && noexcept { return 10; }
|
||||
|
||||
int const_method_rref() const && { return 11; }
|
||||
int const_method_noexcept_rref() const && noexcept { return 12; }
|
||||
|
||||
//
|
||||
|
||||
int non_const_method_volatile() volatile { return 1; }
|
||||
int non_const_method_noexcept_volatile() volatile noexcept { return 2; }
|
||||
|
||||
int const_method_volatile() volatile const { return 3; }
|
||||
int const_method_noexcept_volatile() volatile const noexcept { return 4; }
|
||||
|
||||
int non_const_method_ref_volatile() volatile & { return 5; }
|
||||
int non_const_method_noexcept_ref_volatile() volatile & noexcept { return 6; }
|
||||
|
||||
int const_method_ref_volatile() volatile const & { return 7; }
|
||||
int const_method_noexcept_ref_volatile() volatile const & noexcept { return 8; }
|
||||
|
||||
int non_const_method_rref_volatile() volatile && { return 9; }
|
||||
int non_const_method_noexcept_rref_volatile() volatile && noexcept { return 10; }
|
||||
|
||||
int const_method_rref_volatile() volatile const && { return 11; }
|
||||
int const_method_noexcept_rref_volatile() volatile const && noexcept { return 12; }
|
||||
};
|
||||
|
||||
struct clazz2 {};
|
||||
}
|
||||
|
||||
TEST_CASE("features/infos/method") {
|
||||
registry db;
|
||||
|
||||
db(
|
||||
class_<clazz>{"clazz"}(
|
||||
method_{"non_const_method", &clazz::non_const_method},
|
||||
method_{"non_const_method_noexcept", &clazz::non_const_method_noexcept},
|
||||
|
||||
method_{"const_method", &clazz::const_method},
|
||||
method_{"const_method_noexcept", &clazz::const_method_noexcept},
|
||||
|
||||
method_{"non_const_method_ref", &clazz::non_const_method_ref},
|
||||
method_{"non_const_method_noexcept_ref", &clazz::non_const_method_noexcept_ref},
|
||||
|
||||
method_{"const_method_ref", &clazz::const_method_ref},
|
||||
method_{"const_method_noexcept_ref", &clazz::const_method_noexcept_ref},
|
||||
|
||||
method_{"non_const_method_rref", &clazz::non_const_method_rref},
|
||||
method_{"non_const_method_noexcept_rref", &clazz::non_const_method_noexcept_rref},
|
||||
|
||||
method_{"const_method_rref", &clazz::const_method_rref},
|
||||
method_{"const_method_noexcept_rref", &clazz::const_method_noexcept_rref},
|
||||
|
||||
//
|
||||
|
||||
method_{"non_const_method_volatile", &clazz::non_const_method_volatile},
|
||||
method_{"non_const_method_noexcept_volatile", &clazz::non_const_method_noexcept_volatile},
|
||||
|
||||
method_{"const_method_volatile", &clazz::const_method_volatile},
|
||||
method_{"const_method_noexcept_volatile", &clazz::const_method_noexcept_volatile},
|
||||
|
||||
method_{"non_const_method_ref_volatile", &clazz::non_const_method_ref_volatile},
|
||||
method_{"non_const_method_noexcept_ref_volatile", &clazz::non_const_method_noexcept_ref_volatile},
|
||||
|
||||
method_{"const_method_ref_volatile", &clazz::const_method_ref_volatile},
|
||||
method_{"const_method_noexcept_ref_volatile", &clazz::const_method_noexcept_ref_volatile},
|
||||
|
||||
method_{"non_const_method_rref_volatile", &clazz::non_const_method_rref_volatile},
|
||||
method_{"non_const_method_noexcept_rref_volatile", &clazz::non_const_method_noexcept_rref_volatile},
|
||||
|
||||
method_{"const_method_rref_volatile", &clazz::const_method_rref_volatile},
|
||||
method_{"const_method_noexcept_rref_volatile", &clazz::const_method_noexcept_rref_volatile}
|
||||
)
|
||||
);
|
||||
|
||||
SUBCASE("non_const_method") {
|
||||
const method_info mi = db.get_method_by_path("clazz::non_const_method");
|
||||
REQUIRE(mi);
|
||||
|
||||
const method_info mi2 = db.get_method_by_path("clazz::non_const_method_volatile");
|
||||
REQUIRE(mi2);
|
||||
|
||||
{
|
||||
CHECK(mi.type().arity() == 0);
|
||||
CHECK(mi.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi.type().flags() == method_flags{});
|
||||
|
||||
CHECK(mi2.type().arity() == 0);
|
||||
CHECK(mi2.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi2.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi2.type().flags() == method_flags::is_volatile);
|
||||
}
|
||||
|
||||
{
|
||||
CHECK(mi.is_invocable_with<clazz&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<const clazz&>());
|
||||
CHECK(mi.is_invocable_with<clazz&&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<const clazz&&>());
|
||||
|
||||
CHECK(mi2.is_invocable_with<clazz&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<const clazz&>());
|
||||
CHECK(mi2.is_invocable_with<clazz&&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<const clazz&&>());
|
||||
}
|
||||
|
||||
{
|
||||
clazz cl;
|
||||
|
||||
CHECK(mi.invoke(cl)->equals(1));
|
||||
CHECK_THROWS(mi.invoke(std::as_const(cl)));
|
||||
CHECK(mi.invoke(std::move(cl))->equals(1));
|
||||
CHECK_THROWS(mi.invoke(std::move(std::as_const(cl))));
|
||||
|
||||
CHECK(mi2.invoke(cl)->equals(1));
|
||||
CHECK_THROWS(mi2.invoke(std::as_const(cl)));
|
||||
CHECK(mi2.invoke(std::move(cl))->equals(1));
|
||||
CHECK_THROWS(mi2.invoke(std::move(std::as_const(cl))));
|
||||
}
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method), clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method), const clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method), clazz&&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method), const clazz&&>);
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_volatile), clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_volatile), const clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_volatile), clazz&&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_volatile), const clazz&&>);
|
||||
}
|
||||
|
||||
SUBCASE("non_const_method_noexcept") {
|
||||
const method_info mi = db.get_method_by_path("clazz::non_const_method_noexcept");
|
||||
REQUIRE(mi);
|
||||
|
||||
const method_info mi2 = db.get_method_by_path("clazz::non_const_method_noexcept_volatile");
|
||||
REQUIRE(mi2);
|
||||
|
||||
{
|
||||
CHECK(mi.type().arity() == 0);
|
||||
CHECK(mi.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi.type().flags() == method_flags::is_noexcept);
|
||||
|
||||
CHECK(mi2.type().arity() == 0);
|
||||
CHECK(mi2.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi2.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi2.type().flags() == (method_flags::is_noexcept | method_flags::is_volatile));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK(mi.is_invocable_with<clazz&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<const clazz&>());
|
||||
CHECK(mi.is_invocable_with<clazz&&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<const clazz&&>());
|
||||
|
||||
CHECK(mi2.is_invocable_with<clazz&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<const clazz&>());
|
||||
CHECK(mi2.is_invocable_with<clazz&&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<const clazz&&>());
|
||||
}
|
||||
|
||||
{
|
||||
clazz cl;
|
||||
|
||||
CHECK(mi.invoke(cl)->equals(2));
|
||||
CHECK_THROWS(mi.invoke(std::as_const(cl)));
|
||||
CHECK(mi.invoke(std::move(cl))->equals(2));
|
||||
CHECK_THROWS(mi.invoke(std::move(std::as_const(cl))));
|
||||
|
||||
CHECK(mi2.invoke(cl)->equals(2));
|
||||
CHECK_THROWS(mi2.invoke(std::as_const(cl)));
|
||||
CHECK(mi2.invoke(std::move(cl))->equals(2));
|
||||
CHECK_THROWS(mi2.invoke(std::move(std::as_const(cl))));
|
||||
}
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_noexcept), clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept), const clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_noexcept), clazz&&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept), const clazz&&>);
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_volatile), clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_volatile), const clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_volatile), clazz&&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_volatile), const clazz&&>);
|
||||
}
|
||||
|
||||
SUBCASE("const_method") {
|
||||
const method_info mi = db.get_method_by_path("clazz::const_method");
|
||||
REQUIRE(mi);
|
||||
|
||||
const method_info mi2 = db.get_method_by_path("clazz::const_method_volatile");
|
||||
REQUIRE(mi2);
|
||||
|
||||
{
|
||||
CHECK(mi.type().arity() == 0);
|
||||
CHECK(mi.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi.type().flags() == method_flags::is_const);
|
||||
|
||||
CHECK(mi2.type().arity() == 0);
|
||||
CHECK(mi2.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi2.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi2.type().flags() == (method_flags::is_const | method_flags::is_volatile));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK(mi.is_invocable_with<clazz&>());
|
||||
CHECK(mi.is_invocable_with<const clazz&>());
|
||||
CHECK(mi.is_invocable_with<clazz&&>());
|
||||
CHECK(mi.is_invocable_with<const clazz&&>());
|
||||
|
||||
CHECK(mi2.is_invocable_with<clazz&>());
|
||||
CHECK(mi2.is_invocable_with<const clazz&>());
|
||||
CHECK(mi2.is_invocable_with<clazz&&>());
|
||||
CHECK(mi2.is_invocable_with<const clazz&&>());
|
||||
}
|
||||
|
||||
{
|
||||
clazz cl;
|
||||
|
||||
CHECK(mi.invoke(cl)->equals(3));
|
||||
CHECK(mi.invoke(std::as_const(cl))->equals(3));
|
||||
CHECK(mi.invoke(std::move(cl))->equals(3));
|
||||
CHECK(mi.invoke(std::move(std::as_const(cl)))->equals(3));
|
||||
|
||||
CHECK(mi2.invoke(cl)->equals(3));
|
||||
CHECK(mi2.invoke(std::as_const(cl))->equals(3));
|
||||
CHECK(mi2.invoke(std::move(cl))->equals(3));
|
||||
CHECK(mi2.invoke(std::move(std::as_const(cl)))->equals(3));
|
||||
}
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method), clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method), const clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method), clazz&&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method), const clazz&&>);
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_volatile), clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_volatile), const clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_volatile), clazz&&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_volatile), const clazz&&>);
|
||||
}
|
||||
|
||||
SUBCASE("const_method_noexcept") {
|
||||
const method_info mi = db.get_method_by_path("clazz::const_method_noexcept");
|
||||
REQUIRE(mi);
|
||||
|
||||
const method_info mi2 = db.get_method_by_path("clazz::const_method_noexcept_volatile");
|
||||
REQUIRE(mi2);
|
||||
|
||||
{
|
||||
CHECK(mi.type().arity() == 0);
|
||||
CHECK(mi.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi.type().flags() == (method_flags::is_const | method_flags::is_noexcept));
|
||||
|
||||
CHECK(mi2.type().arity() == 0);
|
||||
CHECK(mi2.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi2.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi2.type().flags() == (method_flags::is_const | method_flags::is_noexcept | method_flags::is_volatile));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK(mi.is_invocable_with<clazz&>());
|
||||
CHECK(mi.is_invocable_with<const clazz&>());
|
||||
CHECK(mi.is_invocable_with<clazz&&>());
|
||||
CHECK(mi.is_invocable_with<const clazz&&>());
|
||||
|
||||
CHECK(mi2.is_invocable_with<clazz&>());
|
||||
CHECK(mi2.is_invocable_with<const clazz&>());
|
||||
CHECK(mi2.is_invocable_with<clazz&&>());
|
||||
CHECK(mi2.is_invocable_with<const clazz&&>());
|
||||
}
|
||||
|
||||
{
|
||||
clazz cl;
|
||||
|
||||
CHECK(mi.invoke(cl)->equals(4));
|
||||
CHECK(mi.invoke(std::as_const(cl))->equals(4));
|
||||
CHECK(mi.invoke(std::move(cl))->equals(4));
|
||||
CHECK(mi.invoke(std::move(std::as_const(cl)))->equals(4));
|
||||
|
||||
CHECK(mi2.invoke(cl)->equals(4));
|
||||
CHECK(mi2.invoke(std::as_const(cl))->equals(4));
|
||||
CHECK(mi2.invoke(std::move(cl))->equals(4));
|
||||
CHECK(mi2.invoke(std::move(std::as_const(cl)))->equals(4));
|
||||
}
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept), clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept), const clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept), clazz&&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept), const clazz&&>);
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_volatile), clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_volatile), const clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_volatile), clazz&&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_volatile), const clazz&&>);
|
||||
}
|
||||
|
||||
SUBCASE("non_const_method_ref") {
|
||||
const method_info mi = db.get_method_by_path("clazz::non_const_method_ref");
|
||||
REQUIRE(mi);
|
||||
|
||||
const method_info mi2 = db.get_method_by_path("clazz::non_const_method_ref_volatile");
|
||||
REQUIRE(mi2);
|
||||
|
||||
{
|
||||
CHECK(mi.type().arity() == 0);
|
||||
CHECK(mi.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi.type().flags() == method_flags::is_lvalue_qualified);
|
||||
|
||||
CHECK(mi2.type().arity() == 0);
|
||||
CHECK(mi2.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi2.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi2.type().flags() == (method_flags::is_volatile | method_flags::is_lvalue_qualified));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK(mi.is_invocable_with<clazz&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<const clazz&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<clazz&&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<const clazz&&>());
|
||||
|
||||
CHECK(mi2.is_invocable_with<clazz&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<const clazz&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<clazz&&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<const clazz&&>());
|
||||
}
|
||||
|
||||
{
|
||||
clazz cl;
|
||||
|
||||
CHECK(mi.invoke(cl)->equals(5));
|
||||
CHECK_THROWS(mi.invoke(std::as_const(cl)));
|
||||
CHECK_THROWS(mi.invoke(std::move(cl)));
|
||||
CHECK_THROWS(mi.invoke(std::move(std::as_const(cl))));
|
||||
|
||||
CHECK(mi2.invoke(cl)->equals(5));
|
||||
CHECK_THROWS(mi2.invoke(std::as_const(cl)));
|
||||
CHECK_THROWS(mi2.invoke(std::move(cl)));
|
||||
CHECK_THROWS(mi2.invoke(std::move(std::as_const(cl))));
|
||||
}
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_ref), clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_ref), const clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_ref), clazz&&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_ref), const clazz&&>);
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_ref_volatile), clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_ref_volatile), const clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_ref_volatile), clazz&&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_ref_volatile), const clazz&&>);
|
||||
}
|
||||
|
||||
SUBCASE("non_const_method_noexcept_ref") {
|
||||
const method_info mi = db.get_method_by_path("clazz::non_const_method_noexcept_ref");
|
||||
REQUIRE(mi);
|
||||
|
||||
const method_info mi2 = db.get_method_by_path("clazz::non_const_method_noexcept_ref_volatile");
|
||||
REQUIRE(mi2);
|
||||
|
||||
{
|
||||
CHECK(mi.type().arity() == 0);
|
||||
CHECK(mi.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi.type().flags() == (method_flags::is_noexcept | method_flags::is_lvalue_qualified));
|
||||
|
||||
CHECK(mi2.type().arity() == 0);
|
||||
CHECK(mi2.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi2.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi2.type().flags() == (method_flags::is_noexcept | method_flags::is_volatile | method_flags::is_lvalue_qualified));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK(mi.is_invocable_with<clazz&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<const clazz&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<clazz&&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<const clazz&&>());
|
||||
|
||||
CHECK(mi2.is_invocable_with<clazz&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<const clazz&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<clazz&&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<const clazz&&>());
|
||||
}
|
||||
|
||||
{
|
||||
clazz cl;
|
||||
|
||||
CHECK(mi.invoke(cl)->equals(6));
|
||||
CHECK_THROWS(mi.invoke(std::as_const(cl)));
|
||||
CHECK_THROWS(mi.invoke(std::move(cl)));
|
||||
CHECK_THROWS(mi.invoke(std::move(std::as_const(cl))));
|
||||
|
||||
CHECK(mi2.invoke(cl)->equals(6));
|
||||
CHECK_THROWS(mi2.invoke(std::as_const(cl)));
|
||||
CHECK_THROWS(mi2.invoke(std::move(cl)));
|
||||
CHECK_THROWS(mi2.invoke(std::move(std::as_const(cl))));
|
||||
}
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_ref), clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_ref), const clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_ref), clazz&&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_ref), const clazz&&>);
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_ref_volatile), clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_ref_volatile), const clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_ref_volatile), clazz&&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_ref_volatile), const clazz&&>);
|
||||
}
|
||||
|
||||
SUBCASE("const_method_ref") {
|
||||
const method_info mi = db.get_method_by_path("clazz::const_method_ref");
|
||||
REQUIRE(mi);
|
||||
|
||||
const method_info mi2 = db.get_method_by_path("clazz::const_method_ref_volatile");
|
||||
REQUIRE(mi2);
|
||||
|
||||
{
|
||||
CHECK(mi.type().arity() == 0);
|
||||
CHECK(mi.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi.type().flags() == (method_flags::is_const | method_flags::is_lvalue_qualified));
|
||||
|
||||
CHECK(mi2.type().arity() == 0);
|
||||
CHECK(mi2.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi2.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi2.type().flags() == (method_flags::is_const | method_flags::is_volatile | method_flags::is_lvalue_qualified));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK(mi.is_invocable_with<clazz&>());
|
||||
CHECK(mi.is_invocable_with<const clazz&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<clazz&&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<const clazz&&>());
|
||||
|
||||
CHECK(mi2.is_invocable_with<clazz&>());
|
||||
CHECK(mi2.is_invocable_with<const clazz&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<clazz&&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<const clazz&&>());
|
||||
}
|
||||
|
||||
{
|
||||
clazz cl;
|
||||
|
||||
CHECK(mi.invoke(cl)->equals(7));
|
||||
CHECK(mi.invoke(std::as_const(cl))->equals(7));
|
||||
CHECK_THROWS(mi.invoke(std::move(cl)));
|
||||
CHECK_THROWS(mi.invoke(std::move(std::as_const(cl))));
|
||||
|
||||
CHECK(mi2.invoke(cl)->equals(7));
|
||||
CHECK(mi2.invoke(std::as_const(cl))->equals(7));
|
||||
CHECK_THROWS(mi2.invoke(std::move(cl)));
|
||||
CHECK_THROWS(mi2.invoke(std::move(std::as_const(cl))));
|
||||
}
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_ref), clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_ref), const clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_ref), clazz&&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_ref), const clazz&&>);
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_ref_volatile), clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_ref_volatile), const clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_ref_volatile), clazz&&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_ref_volatile), const clazz&&>);
|
||||
}
|
||||
|
||||
SUBCASE("const_method_noexcept_ref") {
|
||||
const method_info mi = db.get_method_by_path("clazz::const_method_noexcept_ref");
|
||||
REQUIRE(mi);
|
||||
|
||||
const method_info mi2 = db.get_method_by_path("clazz::const_method_noexcept_ref_volatile");
|
||||
REQUIRE(mi2);
|
||||
|
||||
{
|
||||
CHECK(mi.type().arity() == 0);
|
||||
CHECK(mi.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi.type().flags() == (method_flags::is_const | method_flags::is_noexcept | method_flags::is_lvalue_qualified));
|
||||
|
||||
CHECK(mi2.type().arity() == 0);
|
||||
CHECK(mi2.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi2.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi2.type().flags() == (method_flags::is_const | method_flags::is_noexcept | method_flags::is_volatile | method_flags::is_lvalue_qualified));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK(mi.is_invocable_with<clazz&>());
|
||||
CHECK(mi.is_invocable_with<const clazz&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<clazz&&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<const clazz&&>());
|
||||
|
||||
CHECK(mi2.is_invocable_with<clazz&>());
|
||||
CHECK(mi2.is_invocable_with<const clazz&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<clazz&&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<const clazz&&>());
|
||||
}
|
||||
|
||||
{
|
||||
clazz cl;
|
||||
|
||||
CHECK(mi.invoke(cl)->equals(8));
|
||||
CHECK(mi.invoke(std::as_const(cl))->equals(8));
|
||||
CHECK_THROWS(mi.invoke(std::move(cl)));
|
||||
CHECK_THROWS(mi.invoke(std::move(std::as_const(cl))));
|
||||
|
||||
CHECK(mi2.invoke(cl)->equals(8));
|
||||
CHECK(mi2.invoke(std::as_const(cl))->equals(8));
|
||||
CHECK_THROWS(mi2.invoke(std::move(cl)));
|
||||
CHECK_THROWS(mi2.invoke(std::move(std::as_const(cl))));
|
||||
}
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_ref), clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_ref), const clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_noexcept_ref), clazz&&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_noexcept_ref), const clazz&&>);
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_ref_volatile), clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_ref_volatile), const clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_noexcept_ref_volatile), clazz&&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_noexcept_ref_volatile), const clazz&&>);
|
||||
}
|
||||
|
||||
SUBCASE("non_const_method_rref") {
|
||||
const method_info mi = db.get_method_by_path("clazz::non_const_method_rref");
|
||||
REQUIRE(mi);
|
||||
|
||||
const method_info mi2 = db.get_method_by_path("clazz::non_const_method_rref_volatile");
|
||||
REQUIRE(mi2);
|
||||
|
||||
{
|
||||
CHECK(mi.type().arity() == 0);
|
||||
CHECK(mi.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi.type().flags() == method_flags::is_rvalue_qualified);
|
||||
|
||||
CHECK(mi2.type().arity() == 0);
|
||||
CHECK(mi2.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi2.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi2.type().flags() == (method_flags::is_volatile | method_flags::is_rvalue_qualified));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK_FALSE(mi.is_invocable_with<clazz&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<const clazz&>());
|
||||
CHECK(mi.is_invocable_with<clazz&&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<const clazz&&>());
|
||||
|
||||
CHECK_FALSE(mi2.is_invocable_with<clazz&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<const clazz&>());
|
||||
CHECK(mi2.is_invocable_with<clazz&&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<const clazz&&>());
|
||||
}
|
||||
|
||||
{
|
||||
clazz cl;
|
||||
|
||||
CHECK_THROWS(mi.invoke(cl));
|
||||
CHECK_THROWS(mi.invoke(std::as_const(cl)));
|
||||
CHECK(mi.invoke(std::move(cl))->equals(9));
|
||||
CHECK_THROWS(mi.invoke(std::move(std::as_const(cl))));
|
||||
|
||||
CHECK_THROWS(mi2.invoke(cl));
|
||||
CHECK_THROWS(mi2.invoke(std::as_const(cl)));
|
||||
CHECK(mi2.invoke(std::move(cl))->equals(9));
|
||||
CHECK_THROWS(mi2.invoke(std::move(std::as_const(cl))));
|
||||
}
|
||||
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_rref), clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_rref), const clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_rref), clazz&&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_rref), const clazz&&>);
|
||||
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_rref_volatile), clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_rref_volatile), const clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_rref_volatile), clazz&&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_rref_volatile), const clazz&&>);
|
||||
}
|
||||
|
||||
SUBCASE("non_const_method_noexcept_rref") {
|
||||
const method_info mi = db.get_method_by_path("clazz::non_const_method_noexcept_rref");
|
||||
REQUIRE(mi);
|
||||
|
||||
const method_info mi2 = db.get_method_by_path("clazz::non_const_method_noexcept_rref_volatile");
|
||||
REQUIRE(mi2);
|
||||
|
||||
{
|
||||
CHECK(mi.type().arity() == 0);
|
||||
CHECK(mi.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi.type().flags() == (method_flags::is_noexcept | method_flags::is_rvalue_qualified));
|
||||
|
||||
CHECK(mi2.type().arity() == 0);
|
||||
CHECK(mi2.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi2.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi2.type().flags() == (method_flags::is_noexcept | method_flags::is_volatile | method_flags::is_rvalue_qualified));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK_FALSE(mi.is_invocable_with<clazz&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<const clazz&>());
|
||||
CHECK(mi.is_invocable_with<clazz&&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<const clazz&&>());
|
||||
|
||||
CHECK_FALSE(mi2.is_invocable_with<clazz&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<const clazz&>());
|
||||
CHECK(mi2.is_invocable_with<clazz&&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<const clazz&&>());
|
||||
}
|
||||
|
||||
{
|
||||
clazz cl;
|
||||
|
||||
CHECK_THROWS(mi.invoke(cl));
|
||||
CHECK_THROWS(mi.invoke(std::as_const(cl)));
|
||||
CHECK(mi.invoke(std::move(cl))->equals(10));
|
||||
CHECK_THROWS(mi.invoke(std::move(std::as_const(cl))));
|
||||
|
||||
CHECK_THROWS(mi2.invoke(cl));
|
||||
CHECK_THROWS(mi2.invoke(std::as_const(cl)));
|
||||
CHECK(mi2.invoke(std::move(cl))->equals(10));
|
||||
CHECK_THROWS(mi2.invoke(std::move(std::as_const(cl))));
|
||||
}
|
||||
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_rref), clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_rref), const clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_rref), clazz&&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_rref), const clazz&&>);
|
||||
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_rref_volatile), clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_rref_volatile), const clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_rref_volatile), clazz&&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::non_const_method_noexcept_rref_volatile), const clazz&&>);
|
||||
}
|
||||
|
||||
SUBCASE("const_method_rref") {
|
||||
const method_info mi = db.get_method_by_path("clazz::const_method_rref");
|
||||
REQUIRE(mi);
|
||||
|
||||
const method_info mi2 = db.get_method_by_path("clazz::const_method_rref_volatile");
|
||||
REQUIRE(mi2);
|
||||
|
||||
{
|
||||
CHECK(mi.type().arity() == 0);
|
||||
CHECK(mi.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi.type().flags() == (method_flags::is_const | method_flags::is_rvalue_qualified));
|
||||
|
||||
CHECK(mi2.type().arity() == 0);
|
||||
CHECK(mi2.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi2.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi2.type().flags() == (method_flags::is_const | method_flags::is_volatile | method_flags::is_rvalue_qualified));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK_FALSE(mi.is_invocable_with<clazz&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<const clazz&>());
|
||||
CHECK(mi.is_invocable_with<clazz&&>());
|
||||
CHECK(mi.is_invocable_with<const clazz&&>());
|
||||
|
||||
CHECK_FALSE(mi2.is_invocable_with<clazz&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<const clazz&>());
|
||||
CHECK(mi2.is_invocable_with<clazz&&>());
|
||||
CHECK(mi2.is_invocable_with<const clazz&&>());
|
||||
}
|
||||
|
||||
{
|
||||
clazz cl;
|
||||
|
||||
CHECK_THROWS(mi.invoke(cl));
|
||||
CHECK_THROWS(mi.invoke(std::as_const(cl)));
|
||||
CHECK(mi.invoke(std::move(cl))->equals(11));
|
||||
CHECK(mi.invoke(std::move(std::as_const(cl)))->equals(11));
|
||||
|
||||
CHECK_THROWS(mi2.invoke(cl));
|
||||
CHECK_THROWS(mi2.invoke(std::as_const(cl)));
|
||||
CHECK(mi2.invoke(std::move(cl))->equals(11));
|
||||
CHECK(mi2.invoke(std::move(std::as_const(cl)))->equals(11));
|
||||
}
|
||||
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_rref), clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_rref), const clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_rref), clazz&&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_rref), const clazz&&>);
|
||||
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_rref_volatile), clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_rref_volatile), const clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_rref_volatile), clazz&&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_rref_volatile), const clazz&&>);
|
||||
}
|
||||
|
||||
SUBCASE("const_method_noexcept_rref") {
|
||||
const method_info mi = db.get_method_by_path("clazz::const_method_noexcept_rref");
|
||||
REQUIRE(mi);
|
||||
|
||||
const method_info mi2 = db.get_method_by_path("clazz::const_method_noexcept_rref_volatile");
|
||||
REQUIRE(mi2);
|
||||
|
||||
{
|
||||
CHECK(mi.type().arity() == 0);
|
||||
CHECK(mi.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi.type().flags() == (method_flags::is_const | method_flags::is_noexcept | method_flags::is_rvalue_qualified));
|
||||
|
||||
CHECK(mi2.type().arity() == 0);
|
||||
CHECK(mi2.type().class_type() == type_db::get<clazz>());
|
||||
CHECK(mi2.type().return_type() == type_db::get<int>());
|
||||
CHECK(mi2.type().flags() == (method_flags::is_const | method_flags::is_noexcept | method_flags::is_volatile | method_flags::is_rvalue_qualified));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK_FALSE(mi.is_invocable_with<clazz&>());
|
||||
CHECK_FALSE(mi.is_invocable_with<const clazz&>());
|
||||
CHECK(mi.is_invocable_with<clazz&&>());
|
||||
CHECK(mi.is_invocable_with<const clazz&&>());
|
||||
|
||||
CHECK_FALSE(mi2.is_invocable_with<clazz&>());
|
||||
CHECK_FALSE(mi2.is_invocable_with<const clazz&>());
|
||||
CHECK(mi2.is_invocable_with<clazz&&>());
|
||||
CHECK(mi2.is_invocable_with<const clazz&&>());
|
||||
}
|
||||
|
||||
{
|
||||
clazz cl;
|
||||
|
||||
CHECK_THROWS(mi.invoke(cl));
|
||||
CHECK_THROWS(mi.invoke(std::as_const(cl)));
|
||||
CHECK(mi.invoke(std::move(cl))->equals(12));
|
||||
CHECK(mi.invoke(std::move(std::as_const(cl)))->equals(12));
|
||||
|
||||
CHECK_THROWS(mi2.invoke(cl));
|
||||
CHECK_THROWS(mi2.invoke(std::as_const(cl)));
|
||||
CHECK(mi2.invoke(std::move(cl))->equals(12));
|
||||
CHECK(mi2.invoke(std::move(std::as_const(cl)))->equals(12));
|
||||
}
|
||||
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_noexcept_rref), clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_noexcept_rref), const clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_rref), clazz&&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_rref), const clazz&&>);
|
||||
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_noexcept_rref_volatile), clazz&>);
|
||||
static_assert(!std::is_invocable_v<decltype(&clazz::const_method_noexcept_rref_volatile), const clazz&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_rref_volatile), clazz&&>);
|
||||
static_assert(std::is_invocable_v<decltype(&clazz::const_method_noexcept_rref_volatile), const clazz&&>);
|
||||
}
|
||||
}
|
||||
|
||||
76
untests/features/utilities/inst_tests.cpp
Normal file
76
untests/features/utilities/inst_tests.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*******************************************************************************
|
||||
* 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 "_utilities_fwd.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace meta_hpp;
|
||||
using namespace std::string_literals;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct ivec2 {
|
||||
int x{};
|
||||
int y{};
|
||||
|
||||
[[maybe_unused]] ivec2() = default;
|
||||
[[maybe_unused]] explicit ivec2(int v): x{v}, y{v} {}
|
||||
[[maybe_unused]] ivec2(int x, int y): x{x}, y{y} {}
|
||||
|
||||
[[maybe_unused]] ivec2(ivec2&& other) noexcept {
|
||||
x = other.x;
|
||||
y = other.y;
|
||||
other.x = 0;
|
||||
other.y = 0;
|
||||
}
|
||||
|
||||
[[maybe_unused]] ivec2(const ivec2& other) noexcept {
|
||||
x = other.x;
|
||||
y = other.y;
|
||||
}
|
||||
|
||||
ivec2& operator=(ivec2&&) = delete;
|
||||
ivec2& operator=(const ivec2&) = delete;
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("features/utilities/inst/type") {
|
||||
SUBCASE("ref") {
|
||||
ivec2 v{1,2};
|
||||
ivec2& vr = v;
|
||||
inst a{vr};
|
||||
|
||||
CHECK(a.raw_type() == type_db::get<ivec2>());
|
||||
CHECK(a.ref_type() == inst::ref_types::ref);
|
||||
}
|
||||
|
||||
SUBCASE("cref") {
|
||||
const ivec2 v{1,2};
|
||||
const ivec2& vr = v;
|
||||
inst a{vr};
|
||||
|
||||
CHECK(a.raw_type() == type_db::get<ivec2>());
|
||||
CHECK(a.ref_type() == inst::ref_types::cref);
|
||||
}
|
||||
|
||||
SUBCASE("rref") {
|
||||
ivec2 v{1,2};
|
||||
inst a{std::move(v)};
|
||||
|
||||
CHECK(a.raw_type() == type_db::get<ivec2>());
|
||||
CHECK(a.ref_type() == inst::ref_types::rref);
|
||||
}
|
||||
|
||||
SUBCASE("crref") {
|
||||
const ivec2 v{1,2};
|
||||
inst a{std::move(v)};
|
||||
|
||||
CHECK(a.raw_type() == type_db::get<ivec2>());
|
||||
CHECK(a.ref_type() == inst::ref_types::crref);
|
||||
}
|
||||
}
|
||||
@@ -10,14 +10,17 @@ namespace
|
||||
{
|
||||
using namespace meta_hpp;
|
||||
using namespace std::string_literals;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct ivec2 {
|
||||
int x{};
|
||||
int y{};
|
||||
|
||||
ivec2() = default;
|
||||
explicit ivec2(int v): x{v}, y{v} {}
|
||||
ivec2(int x, int y): x{x}, y{y} {}
|
||||
[[maybe_unused]] ivec2() = default;
|
||||
[[maybe_unused]] explicit ivec2(int v): x{v}, y{v} {}
|
||||
[[maybe_unused]] ivec2(int x, int y): x{x}, y{y} {}
|
||||
|
||||
ivec2(ivec2&& other) noexcept
|
||||
: x{other.x}
|
||||
|
||||
Reference in New Issue
Block a user