Skip to content

Commit 942a4f8

Browse files
committed
Corrected deducer with aggregate initalization
1 parent dd6a5a1 commit 942a4f8

File tree

5 files changed

+513
-345
lines changed

5 files changed

+513
-345
lines changed

include/kangaru/detail/constructor.hpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,19 @@
1515

1616
KANGARU5_EXPORT namespace kangaru {
1717
template<typename T, typename... Args>
18-
concept raw_constructor_callable = std::constructible_from<T, Args...> or brace_constructible<T, Args...>;
18+
concept raw_constructor_callable =
19+
std::constructible_from<T, Args...>
20+
or (
21+
brace_constructible<T, Args...>
22+
and (
23+
not std::is_aggregate_v<T>
24+
or sizeof...(Args) != 1
25+
)
26+
);
1927

2028
template<unqualified_object Type>
2129
struct raw_constructor_function {
22-
constexpr auto operator()(auto&&... args) const& requires(
30+
constexpr auto operator()(auto&&... args) const& -> Type requires(
2331
raw_constructor_callable<Type, decltype(args)...>
2432
) {
2533
if constexpr (std::constructible_from<Type, decltype(args)...>) {

include/kangaru/detail/deducer.hpp

Lines changed: 118 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ namespace kangaru {
117117
operator T const& () const;
118118
#endif
119119

120+
#if KANGARU5_RVALUE_CONST_AMBIGUOUS()
121+
template<deducible T>
122+
operator T const&& () const;
123+
#endif
124+
120125
#if KANGARU5_RVALUE_AMBIGUOUS()
121126
template<typename T>
122127
operator T&& () const;
@@ -127,20 +132,19 @@ namespace kangaru {
127132
using is_deducer = kangaru_deducer_tag;
128133

129134
template<deducible T>
130-
operator T () const;
135+
operator T ();
131136

132137
template<deducible T>
133-
operator T& ();
138+
operator T& () const;
134139

135-
#if KANGARU5_LVALUE_CONST_AMBIGUOUS()
136140
template<deducible T>
137-
operator T const& ();
138-
#endif
141+
operator T const& () const;
142+
143+
template<deducible T>
144+
operator T const&& () const;
139145

140-
#if KANGARU5_RVALUE_AMBIGUOUS()
141146
template<typename T>
142-
operator T&& ();
143-
#endif
147+
operator T&& () const;
144148
};
145149

146150
KANGARU5_EXPORT struct placeholder_deducer {
@@ -555,42 +559,118 @@ namespace kangaru {
555559
}
556560

557561
namespace detail::deducer {
562+
template<typename T, typename F, typename, typename>
563+
inline constexpr auto callable_with_nth_parameter_being_expand = false;
564+
558565
template<typename T, typename F, std::size_t... before, std::size_t... after>
559-
inline consteval auto callable_with_nth_parameter_being_expand(std::index_sequence<before...>, std::index_sequence<after...>) -> bool {
560-
return callable<
566+
inline constexpr auto callable_with_nth_parameter_being_expand<T, F, std::index_sequence<before...>, std::index_sequence<after...>> =
567+
callable<
561568
F,
562569
detail::utility::expand<placeholder_deducer, before>...,
563570
T,
564571
detail::utility::expand<placeholder_deducer, after>...
565572
>;
566-
}
567573

568574
template<typename T, typename F, std::size_t nth, std::size_t max>
569-
inline constexpr auto callable_with_nth_parameter_being = bool{
570-
KANGARU5_NO_ADL(callable_with_nth_parameter_being_expand<T, F>)(std::make_index_sequence<nth>{}, std::make_index_sequence<max - nth - 1>{})
571-
};
575+
concept callable_with_nth_parameter_being =
576+
callable_with_nth_parameter_being_expand<T, F, std::make_index_sequence<nth>, std::make_index_sequence<max - nth - 1>>;
572577

573578
template<typename F, std::size_t nth, std::size_t max>
574-
inline constexpr auto is_nth_parameter_prvalue = bool{
579+
concept function_nth_parameter_prvalue =
575580
not callable_with_nth_parameter_being<ambiguous_prvalue_deducer, F, nth, max>
576-
and callable_with_nth_parameter_being<ambiguous_overloaded_reference_deducer, F, nth, max>
577-
};
581+
and callable_with_nth_parameter_being<ambiguous_overloaded_reference_deducer, F, nth, max>;
582+
583+
template<typename T, typename F, std::size_t nth, std::size_t max>
584+
concept callable_with_lvalue_const_ref = callable_with_nth_parameter_being<
585+
filtered_value_category_deducer<T, reference_kind::lvalue_const_reference>,
586+
F,
587+
nth,
588+
max
589+
>;
590+
591+
// TODO: Remove conditionals, convert to pure boolean expressions
592+
template<typename T, typename F, std::size_t nth, std::size_t max>
593+
concept callable_with_rvalue_const_ref = (
594+
callable_with_lvalue_const_ref<T, F, nth, max>
595+
? not callable_with_nth_parameter_being<
596+
filtered_value_category_deducer<T, reference_kind::lvalue_const_reference_and_rvalue_const_reference>,
597+
F,
598+
nth,
599+
max
600+
>
601+
: (
602+
callable_with_nth_parameter_being<
603+
filtered_value_category_deducer<T, reference_kind::rvalue_const_reference>,
604+
F,
605+
nth,
606+
max
607+
> or (
608+
callable_with_nth_parameter_being<
609+
filtered_value_category_deducer<T, reference_kind::rvalue_reference>,
610+
F,
611+
nth,
612+
max
613+
> and not callable_with_nth_parameter_being<
614+
filtered_value_category_deducer<T, reference_kind::rvalue_reference_and_rvalue_const_reference>,
615+
F,
616+
nth,
617+
max
618+
>
619+
)
620+
)
621+
);
622+
623+
template<typename T, typename F, std::size_t nth, std::size_t max>
624+
constexpr auto callable_with_lvalue_ref =
625+
callable_with_lvalue_const_ref<T, F, nth, max>
626+
? not callable_with_nth_parameter_being<
627+
filtered_value_category_deducer<T, reference_kind::lvalue_reference_and_lvalue_const_reference>,
628+
F,
629+
nth,
630+
max
631+
>
632+
: callable_with_nth_parameter_being<
633+
filtered_value_category_deducer<T, reference_kind::lvalue_reference>,
634+
F,
635+
nth,
636+
max
637+
>;
638+
639+
template<typename T, typename F, std::size_t nth, std::size_t max>
640+
constexpr auto callable_with_rvalue_ref =
641+
callable_with_rvalue_const_ref<T, F, nth, max>
642+
? not callable_with_nth_parameter_being<
643+
filtered_value_category_deducer<T, reference_kind::rvalue_reference_and_rvalue_const_reference>,
644+
F,
645+
nth,
646+
max
647+
>
648+
: callable_with_lvalue_const_ref<T, F, nth, max>
649+
? not callable_with_nth_parameter_being<
650+
filtered_value_category_deducer<T, reference_kind::lvalue_const_reference_and_rvalue_reference>,
651+
F,
652+
nth,
653+
max
654+
>
655+
: callable_with_nth_parameter_being<
656+
filtered_value_category_deducer<T, reference_kind::rvalue_reference>,
657+
F,
658+
nth,
659+
max
660+
>;
578661

579662
template<typename T, typename F, std::size_t nth, std::size_t max>
580663
inline consteval auto reference_kind_for_nth_parameter() -> reference_kind {
581-
if constexpr (is_nth_parameter_prvalue<F, nth, max>) {
664+
if constexpr (function_nth_parameter_prvalue<F, nth, max>) {
582665
return reference_kind::none;
583666
} else {
584667
// Welcome to insanity
585668

586669
// Only one kind of parameter will accept a lvalue const reference, and it's a lvalue const reference.
587670
// If the function is callable with a lvalue const reference, then it means there's an overload that accepts it.
588-
constexpr auto callable_with_lvalue_const_ref = callable_with_nth_parameter_being<
589-
filtered_value_category_deducer<T, reference_kind::lvalue_const_reference>,
590-
F,
591-
nth,
592-
max
593-
>;
671+
constexpr auto lvalue_const_ref = callable_with_lvalue_const_ref<T, F, nth, max>
672+
? reference_kind::lvalue_const_reference
673+
: reference_kind::none;
594674

595675
// Now we have something harder to match. Sending a rvalue constant reference would indeed match a rvalue
596676
// constant reference parameter, but would also match a lvalue constant reference. This means that if we
@@ -604,82 +684,31 @@ namespace kangaru {
604684
// On the contrary, if there was no match for lvalue constant reference:
605685
// - We match for rvalue constant reference. If it matches, we're gold.
606686
// - If we don't match, we exclude matching with mutable rvalue for clang
607-
constexpr auto callable_with_rvalue_const_ref = callable_with_lvalue_const_ref
608-
? not callable_with_nth_parameter_being<
609-
filtered_value_category_deducer<T, reference_kind::lvalue_const_reference_and_rvalue_const_reference>,
610-
F,
611-
nth,
612-
max
613-
>
614-
: (
615-
callable_with_nth_parameter_being<
616-
filtered_value_category_deducer<T, reference_kind::rvalue_const_reference>,
617-
F,
618-
nth,
619-
max
620-
> or (
621-
callable_with_nth_parameter_being<
622-
filtered_value_category_deducer<T, reference_kind::rvalue_reference>,
623-
F,
624-
nth,
625-
max
626-
> and not callable_with_nth_parameter_being<
627-
filtered_value_category_deducer<T, reference_kind::rvalue_reference_and_rvalue_const_reference>,
628-
F,
629-
nth,
630-
max
631-
>
632-
)
633-
);
687+
constexpr auto rvalue_const_ref = callable_with_rvalue_const_ref<T, F, nth, max>
688+
? reference_kind::rvalue_const_reference
689+
: reference_kind::none;
634690

635691
// To check for normal lvalue references, we need to first check if we already match with a const reference.
636692
// If we did match, then we'll do the trick where we try to call the function with a deducer that can
637693
// Deduce both kind. If the call is ambiguous, then we have a candidate in the overload set that take a lvalue ref.
638694
// Otherwise, we can just match with lvalue references.
639-
constexpr auto callable_with_lvalue_ref = callable_with_lvalue_const_ref
640-
? not callable_with_nth_parameter_being<
641-
filtered_value_category_deducer<T, reference_kind::lvalue_reference_and_lvalue_const_reference>,
642-
F,
643-
nth,
644-
max
645-
>
646-
: callable_with_nth_parameter_being<
647-
filtered_value_category_deducer<T, reference_kind::lvalue_reference>,
648-
F,
649-
nth,
650-
max
651-
>;
695+
constexpr auto lvalue_ref = callable_with_lvalue_ref<T, F, nth, max>
696+
? reference_kind::lvalue_reference
697+
: reference_kind::none;
652698

653699
// Here we finally check for rvalue references. They can match rvalue references, rvalue const references, and
654700
// lvalue const references. We need take into account if we matched for them them before in order to do the right
655701
// little dance of ambiguous call check.
656-
constexpr auto callable_with_rvalue_ref = callable_with_rvalue_const_ref
657-
? not callable_with_nth_parameter_being<
658-
filtered_value_category_deducer<T, reference_kind::rvalue_reference_and_rvalue_const_reference>,
659-
F,
660-
nth,
661-
max
662-
>
663-
: callable_with_lvalue_const_ref
664-
? not callable_with_nth_parameter_being<
665-
filtered_value_category_deducer<T, reference_kind::lvalue_const_reference_and_rvalue_reference>,
666-
F,
667-
nth,
668-
max
669-
>
670-
: callable_with_nth_parameter_being<
671-
filtered_value_category_deducer<T, reference_kind::rvalue_reference>,
672-
F,
673-
nth,
674-
max
675-
>;
702+
constexpr auto rvalue_ref = callable_with_rvalue_ref<T, F, nth, max>
703+
? reference_kind::rvalue_reference
704+
: reference_kind::none;
676705

677706
// We build the bitmask enum to express what overloads of different reference kind exists
678707
return (
679-
(callable_with_lvalue_ref ? reference_kind::lvalue_reference : reference_kind::none)
680-
| (callable_with_lvalue_const_ref ? reference_kind::lvalue_const_reference : reference_kind::none)
681-
| (callable_with_rvalue_ref ? reference_kind::rvalue_reference : reference_kind::none)
682-
| (callable_with_rvalue_const_ref ? reference_kind::rvalue_const_reference : reference_kind::none)
708+
lvalue_ref
709+
| lvalue_const_ref
710+
| rvalue_ref
711+
| rvalue_const_ref
683712
);
684713
}
685714
}
@@ -692,7 +721,7 @@ namespace kangaru {
692721

693722
template<typename F, typename Deducer, std::size_t nth, std::size_t arity>
694723
using prvalue_filtered_deducer_for = detail::type_traits::conditional_t<
695-
not is_nth_parameter_prvalue<F, nth, arity>
724+
not function_nth_parameter_prvalue<F, nth, arity>
696725
and callable_with_nth_parameter_being<exclude_prvalue_deducer<Deducer>, F, nth, arity>,
697726
exclude_prvalue_deducer<Deducer>,
698727
exclude_references_deducer<Deducer>

include/kangaru/detail/define.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#define KANGARU5_NO_UNIQUE_ADDRESS [[no_unique_address]]
3838
#define KANGARU5_INLINE [[clang::always_inline]]
3939
#define KANGARU5_RVALUE_AMBIGUOUS() false
40+
#define KANGARU5_RVALUE_CONST_AMBIGUOUS() false
4041
#define KANGARU5_LVALUE_CONST_AMBIGUOUS() true
4142
#define KANGARU5_FUNCTION_SIGNATURE __PRETTY_FUNCTION__
4243

@@ -57,6 +58,7 @@
5758
#define KANGARU5_NO_UNIQUE_ADDRESS [[no_unique_address]]
5859
#define KANGARU5_INLINE [[gnu::always_inline]]
5960
#define KANGARU5_RVALUE_AMBIGUOUS() true
61+
#define KANGARU5_RVALUE_CONST_AMBIGUOUS() true
6062
#define KANGARU5_LVALUE_CONST_AMBIGUOUS() false
6163
#define KANGARU5_FUNCTION_SIGNATURE __PRETTY_FUNCTION__
6264
#define KANGARU5_CONSTEXPR_VOIDSTAR_CAST_SUPPORTED() (__cpp_constexpr >= 202306L)
@@ -72,6 +74,7 @@
7274
#define KANGARU5_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
7375
#define KANGARU5_INLINE [[msvc::forceinline]]
7476
#define KANGARU5_RVALUE_AMBIGUOUS() false
77+
#define KANGARU5_RVALUE_CONST_AMBIGUOUS() false
7578
#define KANGARU5_LVALUE_CONST_AMBIGUOUS() true
7679
#define KANGARU5_FUNCTION_SIGNATURE __FUNCSIG__
7780

tests/src/5-modular-source.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "kangaru/detail/deducer.hpp"
12
#include "kangaru/detail/injector.hpp"
23
#include "kangaru/detail/recursive_source.hpp"
34
#include "kangaru/detail/source.hpp"
@@ -419,12 +420,9 @@ namespace kangaru {
419420
}
420421

421422
// Here's many classes, all have some relations with others
422-
423423
struct service_1_a { int i; };
424424
struct service_1_b { service_1_a& s1a; int i; };
425-
426-
// TODO: Investigate why an aggregate containing one dependency fails to be injected
427-
struct service_1_c { service_1_b s1b; service_1_a& s1a; };
425+
struct service_1_c { service_1_b s1b; };
428426

429427
struct agg1 {
430428
service_1_a& a;
@@ -450,11 +448,8 @@ struct agg2 {
450448
service_2_a& s2a;
451449
};
452450

453-
// TODO: Figure out how to properly inject aggregate bases.
454451
struct service_3_a_base { service_2_b& s2b; service_1_a& s1a; };
455-
struct service_3_a : service_3_a_base {
456-
explicit constexpr service_3_a(service_2_b& s2b, service_1_a& s1a) : service_3_a_base{.s2b = s2b, .s1a = s1a} {}
457-
};
452+
struct service_3_a : service_3_a_base {};
458453

459454
struct service_3_b_base {};
460455
struct service_3_b : service_3_b_base {

0 commit comments

Comments
 (0)