Skip to content

Commit a6df5bd

Browse files
committed
rework overriders
1 parent 44003c2 commit a6df5bd

File tree

4 files changed

+132
-49
lines changed

4 files changed

+132
-49
lines changed

include/yorel/yomm2/core.hpp

Lines changed: 82 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,6 @@ class method<Name, Return(Parameters...), Options...>
649649
using Signature = Return(Parameters...);
650650
using FunctionPointer =
651651
Return (*)(detail::remove_virtual<Parameters>...) noexcept(NoExcept);
652-
using Next = FunctionPointer;
653652

654653
static constexpr auto arity = detail::arity<Parameters...>;
655654
static_assert(arity > 0, "method must have at least one virtual argument");
@@ -703,42 +702,13 @@ class method<Name, Return(Parameters...), Options...>
703702
template<auto, typename>
704703
struct thunk;
705704

706-
template<
707-
auto Overrider, typename OverriderReturn,
708-
typename... OverriderParameters>
709-
struct thunk<Overrider, OverriderReturn (*)(OverriderParameters...)> {
710-
static auto fn(detail::remove_virtual<Parameters>... arg) -> Return;
711-
using OverriderParameterTypeIds = detail::type_id_list<
712-
Policy,
713-
detail::spec_polymorphic_types<
714-
Policy, DeclaredParameters,
715-
detail::types<OverriderParameters...>>>;
716-
};
717-
718-
template<class Container, bool has_next>
719-
struct override_;
720-
721705
friend class generator;
722706

723-
public:
724-
template<auto Function>
725-
struct override_fn;
726-
727-
private:
728-
template<class Container>
729-
struct override_<Container, false> {
730-
override_fn<Container::fn> override_{nullptr};
731-
};
732-
733-
template<class Container>
734-
struct override_<Container, true> {
735-
override_fn<Container::fn> add{&Container::next};
736-
};
737-
738707
public:
739708
// Public aliases.
740709
using return_type = Return;
741-
using next_type = Next;
710+
using next_type =
711+
Return (*)(detail::remove_virtual<Parameters>...) noexcept(NoExcept);
742712

743713
static method fn;
744714

@@ -753,9 +723,31 @@ class method<Name, Return(Parameters...), Options...>
753723
template<class Container>
754724
using next = detail::next_aux<method, Container>;
755725

726+
template<auto>
727+
static FunctionPointer next_fn;
728+
729+
private:
730+
template<
731+
auto Overrider, typename OverriderReturn,
732+
typename... OverriderParameters>
733+
struct thunk<Overrider, OverriderReturn (*)(OverriderParameters...)> {
734+
static auto fn(detail::remove_virtual<Parameters>... arg) -> Return;
735+
using OverriderParameterTypeIds = detail::type_id_list<
736+
Policy,
737+
detail::spec_polymorphic_types<
738+
Policy, DeclaredParameters,
739+
detail::types<OverriderParameters...>>>;
740+
};
741+
756742
template<auto Function>
757-
struct override_fn {
758-
explicit override_fn(Next* next = nullptr) {
743+
struct override_fn_impl {
744+
explicit override_fn_impl(FunctionPointer* next = nullptr) {
745+
// Work around MSVC bug: using &next_fn<Function> as a default value
746+
// for 'next' confuses it about Parameters not being expanded.
747+
if (!next) {
748+
next = &next_fn<Function>;
749+
}
750+
759751
static detail::definition_info info;
760752

761753
if (info.method) {
@@ -774,25 +766,73 @@ class method<Name, Return(Parameters...), Options...>
774766
}
775767
};
776768

777-
template<class Container>
778-
struct override
779-
: override_<Container, detail::has_next<Container>::value> {
780-
using type = override; // make it a meta-function
769+
template<auto Function, typename FunctionType>
770+
struct override_fn_aux;
771+
772+
template<auto Function, typename FnReturnType, typename... FnParameters>
773+
struct override_fn_aux<Function, FnReturnType (*)(FnParameters...)>
774+
: override_fn_impl<Function> {
775+
using override_fn_impl<Function>::override_fn_impl;
776+
};
777+
778+
template<
779+
auto Function, class FnClass, typename FnReturnType,
780+
typename... FnParameters>
781+
struct override_fn_aux<
782+
Function, FnReturnType (FnClass::*)(FnParameters...)> {
783+
static auto fn(FnClass* this_, FnParameters&&... args) -> FnReturnType {
784+
return (this_->*Function)(std::forward<FnParameters>(args)...);
785+
}
786+
787+
override_fn_impl<fn> impl{&next_fn<Function>};
781788
};
782789

783-
template<auto F>
784-
struct add_member_function
785-
: override_fn<detail::member_function_thunk<F, decltype(F)>::fn> {};
790+
public:
791+
template<auto Function>
792+
struct override_fn : override_fn_aux<Function, decltype(Function)> {
793+
using override_fn_aux<Function, decltype(Function)>::override_fn_aux;
794+
};
786795

787796
template<auto... F>
788-
struct add_member_functions : std::tuple<add_member_function<F>...> {};
797+
struct override_fns {
798+
std::tuple<override_fn<F>...> fns;
799+
};
800+
801+
private:
802+
template<class Container, bool HasNext>
803+
struct override_aux;
804+
805+
template<class Container>
806+
struct override_aux<Container, false> : override_fn<Container::fn> {
807+
override_aux() : override_fn<Container::fn>(nullptr) {
808+
}
809+
};
810+
811+
template<class Container>
812+
struct override_aux<Container, true> : override_fn<Container::fn> {
813+
override_aux() : override_fn<Container::fn>(&Container::next) {
814+
}
815+
};
816+
817+
public:
818+
template<class Container>
819+
struct override
820+
: override_aux<Container, detail::has_next<Container>::value> {
821+
using type = override; // make it a meta-function
822+
};
789823
};
790824

791825
template<
792826
typename Name, typename Return, typename... Parameters, class... Options>
793827
method<Name, Return(Parameters...), Options...>
794828
method<Name, Return(Parameters...), Options...>::fn;
795829

830+
template<
831+
typename Name, typename Return, typename... Parameters, class... Options>
832+
template<auto>
833+
typename method<Name, Return(Parameters...), Options...>::FunctionPointer
834+
method<Name, Return(Parameters...), Options...>::next_fn;
835+
796836
template<typename T>
797837
constexpr bool is_method = std::is_base_of_v<detail::method_info, T>;
798838

include/yorel/yomm2/macros.hpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,10 @@
5151
YOMM2_SYMBOL(NAME), RETURN_TYPE ARGS, \
5252
::yorel::yomm2::detail::types<__VA_ARGS__>>::type
5353

54-
#define YOMM2_DECLARE(...) yOMM2_DECLARE(yOMM2_WHEN_NOT_STATIC, __VA_ARGS__)
55-
#define YOMM2_STATIC_DECLARE(...) yOMM2_DECLARE(yOMM2_WHEN_STATIC, __VA_ARGS__)
54+
#define YOMM2_DECLARE(RETURN_TYPE, NAME, ARGS, ...) \
55+
yOMM2_DECLARE(yOMM2_WHEN_NOT_STATIC, RETURN_TYPE, NAME, ARGS, __VA_ARGS__)
56+
#define YOMM2_STATIC_DECLARE(RETURN_TYPE, NAME, ARGS, ...) \
57+
yOMM2_DECLARE(yOMM2_WHEN_STATIC, RETURN_TYPE, NAME, ARGS, __VA_ARGS__)
5658

5759
#define yOMM2_DECLARE(IF_STATIC, RETURN_TYPE, NAME, ARGS, ...) \
5860
struct YOMM2_SYMBOL(NAME); \
@@ -112,7 +114,7 @@
112114
struct _yOMM2_spec { \
113115
static NS::_yOMM2_method::return_type yOMM2_body ARGS; \
114116
}; \
115-
_yOMM2_method::override_fn<_yOMM2_spec::yOMM2_body> YOMM2_GENSYM(&next); \
117+
_yOMM2_method::override_fn<_yOMM2_spec::yOMM2_body> YOMM2_GENSYM(&next); \
116118
} \
117119
} \
118120
NS::_yOMM2_method::return_type NS::_yOMM2_spec::yOMM2_body ARGS
@@ -165,7 +167,7 @@
165167
Inline NS::_yOMM2_method::next_type CONTAINER<RETURN_TYPE ARGS>::next; \
166168
namespace { \
167169
namespace NS { \
168-
Inline _yOMM2_method::override_fn<CONTAINER<RETURN_TYPE ARGS>::fn> \
170+
Inline _yOMM2_method::override_fn<CONTAINER<RETURN_TYPE ARGS>::fn> \
169171
YOMM2_GENSYM(&CONTAINER<RETURN_TYPE ARGS>::next); \
170172
} \
171173
} \

tests/test_blackbox.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,45 @@ BOOST_AUTO_TEST_CASE(simple) {
203203

204204
} // namespace matrices
205205

206+
namespace test_next_fn {
207+
208+
struct Animal {
209+
virtual ~Animal() {
210+
}
211+
};
212+
213+
struct Dog : Animal {};
214+
struct Bulldog : Dog {};
215+
216+
register_classes(Animal, Dog, Bulldog);
217+
218+
struct YOMM2_SYMBOL(kick);
219+
using kick = method<YOMM2_SYMBOL(kick), std::string(virtual_<Animal&>)>;
220+
221+
std::string kick_dog(Dog& dog) {
222+
return "bark";
223+
}
224+
225+
YOMM2_STATIC(kick::override_fn<kick_dog>);
226+
227+
std::string kick_bulldog(Bulldog& dog) {
228+
return kick::next_fn<kick_bulldog>(dog) + " and bite back";
229+
}
230+
231+
YOMM2_STATIC(kick::override_fn<kick_bulldog>);
232+
233+
BOOST_AUTO_TEST_CASE(test_next_fn) {
234+
update();
235+
236+
std::unique_ptr<Animal> snoopy = std::make_unique<Dog>();
237+
BOOST_TEST(kick::fn(*snoopy) == "bark");
238+
239+
std::unique_ptr<Animal> hector = std::make_unique<Bulldog>();
240+
BOOST_TEST(kick::fn(*hector) == "bark and bite back");
241+
}
242+
243+
} // namespace test_next_fn
244+
206245
namespace errors {
207246

208247
struct matrix {

tests/test_member_method.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,14 @@ struct Payroll {
3939
void pay_employee(const Employee&) {
4040
balance -= 2000;
4141
}
42-
void pay_manager(const Manager&) {
43-
balance -= 3000;
42+
void pay_manager(const Manager& manager) {
43+
auto pf = &pay_method::next_fn<&Payroll::pay_manager>;
44+
pay_method::next_fn<&Payroll::pay_manager>(this, manager);
45+
balance -= 1000;
4446
}
4547

4648
public:
47-
using pay_functions = Payroll::pay_method::add_member_functions<
49+
using pay_functions = Payroll::pay_method::override_fns<
4850
&Payroll::pay_employee, &Payroll::pay_manager>;
4951
};
5052

0 commit comments

Comments
 (0)