Example
template<class TPolicy>
struct foo : TPolicy {
static constexpr auto bar() {
return TPolicy::bar();
}
};
template<auto N>
struct policy { static constexpr auto bar() { return N; } };
static_assert(0 == foo<policy<0>>::bar());
static_assert(42 == foo<policy<42>>::bar());
Puzzle
-
Can you implement
foo::bar
which is noexcept whennoexcept_policy
is set and returns a sum ofexecute_policy::bar
calls?- Types not satisfying any policy should be ignored
- Double points for explaining what advantages
Policy Based Design
has over passingEnums/Booleans
?
template<class... TPolicies>
struct foo {
static constexpr auto bar() noexcept/*TODO*/ {
return 0;/*TODO*/
}
};
template<auto N> struct execute_policy { static constexpr auto bar() { return N; } };
struct noexcept_policy { };
struct ignore { };
static_assert(not noexcept(foo<>::bar()));
static_assert(not noexcept(foo<ignore>::bar()));
static_assert(noexcept(foo<noexcept_policy>::bar()));
static_assert(noexcept(foo<noexcept_policy, ignore>::bar()));
static_assert(noexcept(foo<ignore, noexcept_policy, ignore>::bar()));
static_assert(noexcept(foo<ignore, noexcept_policy, ignore, execute_policy<0>>::bar()));
static_assert(42 == foo<execute_policy<42>>::bar());
static_assert(42 == foo<ignore, execute_policy<42>>::bar());
static_assert(42 == foo<ignore, execute_policy<42>, ignore>::bar());
static_assert(100 == foo<ignore, execute_policy<42>, ignore, execute_policy<58>>::bar());
static_assert(3 == foo<execute_policy<1>, noexcept_policy, execute_policy<2>, noexcept_policy>::bar());
Solutions
template<class... TPolicies>
struct foo {
template<class T > struct no_bar{ constexpr static bool value = !requires{ T::bar();}; };
static constexpr auto bar() noexcept( !std::is_same_v< mp_find<mp_list<TPolicies...>, class noexcept_policy >, mp_size<mp_list<TPolicies...> > > )/*TODO*/ {
using L = mp_remove_if<mp_list< TPolicies... >, no_bar >;
return []< class ... Ts >( mp_list<Ts... > ){ return ( (Ts::bar()) + ... + 0 ) ;}( L{} );
}
};
// Advantages of policies? They're basically the https://en.wikipedia.org/wiki/Strategy_pattern
// Decoupled interfaces, adherence to the open/closed principle, etc.
template<class... TPolicies>
struct foo {
static constexpr auto bar() noexcept((std::is_same_v<TPolicies, struct noexcept_policy> or ...)) {
constexpr auto run_bar = []<class TPolicy>() {
if constexpr (requires { TPolicy::bar(); }) {
return TPolicy::bar();
} else {
return 0;
}
};
return (0 + ... + run_bar.template operator()<TPolicies>());
}
};
struct noexcept_policy { };
template<class...>
struct has_noexcept_policy;
template<>
struct has_noexcept_policy<> {
static constexpr auto value = false;
};
template<class T, class... Ts>
struct has_noexcept_policy<T, Ts...> {
static constexpr auto value = [] {
if constexpr (std::is_same_v<T, noexcept_policy>) {
return true;
} else {
return has_noexcept_policy<Ts...>::value;
}
}();
};
template<class TPolicy>
struct execute_policy_bar {
static constexpr auto value = [] {
if constexpr (requires { { TPolicy::bar() } -> std::integral; }) {
return TPolicy::bar();
} else {
return 0;
}
}();
};
template<class... TPolicies>
struct foo {
static constexpr auto bar() noexcept(has_noexcept_policy<TPolicies...>::value) {
return (0 + ... + execute_policy_bar<TPolicies>::value);
}
};
namespace detail {
template<class T>
concept has_func_bar = requires { T::bar(); };
}
template<class... TPolicies>
struct foo {
static constexpr auto has_noexcept_policy = (std::is_same_v<TPolicies, struct noexcept_policy> or ...);
[[nodiscard]] static constexpr auto bar() noexcept(has_noexcept_policy) {
[[maybe_unused]] constexpr auto run_execute_policy = []<class TPolicy>(){
if constexpr(detail::has_func_bar<TPolicy>) {
return TPolicy{}.bar();
} else {
return 0;
}
};
return (run_execute_policy.template operator()<TPolicies>() + ... + 0);
}
};
template<typename T> concept HasBar = requires(T) { T::bar(); };
template<HasBar T> auto constexpr CallBar() { return T::bar(); }
template<typename T> auto constexpr CallBar() { return 0; }
template<class... TPolicies>
struct foo {
static constexpr auto bar() noexcept((std::is_same_v<TPolicies, noexcept_policy> || ...)) {
return (CallBar<TPolicies>() + ...+ 0);
}
};
template<class... TPolicies>
struct foo {
static constexpr auto bar() noexcept((std::is_same_v<struct noexcept_policy, TPolicies> or ...)) {
return ([] {
if constexpr (requires { TPolicies::bar(); }) {
return TPolicies::bar();
} else {
return 0;
}
}() + ... + 0);
}
};