Info
-
Did you know that Lambdas in Unevaluated Context combined with Immediately Invoked Function Expressions (IIFE) can be used to simplify Template Meta-Programming?
Example
static_assert(not std::is_same_v<decltype([]{}), decltype([]{})>);
static_assert(std::is_same_v<void, decltype([]{}())>);
static_assert(std::is_same_v<decltype([]{}()), decltype([]{}())>);
Puzzle
-
Can you implement an
add_pointer
routine which makes the usage ofdecltype(IIFE)
and returns a list of pointer types to: {value
field if present,void
otherwise }?- Consider applying C++20 concepts and Design by Introspection for fields detection
template<class...> struct type_list {};
template<class... Ts>
constinit auto add_pointer = type_list</*TODO*/>{};
struct foo {
int value;
};
struct bar { };
static_assert(std::is_same_v<type_list<>, decltype(add_pointer<>)>);
static_assert(std::is_same_v<type_list<int*>, decltype(add_pointer<foo>)>);
static_assert(std::is_same_v<type_list<void*>, decltype(add_pointer<bar>)>);
static_assert(std::is_same_v<type_list<int*, void*>, decltype(add_pointer<foo, bar>)>);
Solutions
constexpr auto value_from = [] (auto t) {
if constexpr (requires { t.value; }) {
return t.value;
}
};
template <class T>
using value_t = std::add_pointer_t<decltype(value_from(std::declval<T>()))>;
template<class... Ts>
constinit auto add_pointer = type_list<value_t<Ts>...>{};
template<class... Ts>
constinit auto add_pointer = type_list<decltype(
[] {
if constexpr (requires(Ts t) { t.value; } ) {
return Ts{}.value;
}
}())*...>{};
template<typename T>
concept HasValue = requires(T t) { t.value; };
auto ValueOrVoidPtr = []<typename T>(const T&) {
if constexpr (HasValue<T>)
return (decltype(T::value)*)(nullptr);
else
return (void*)(nullptr);
};
template<class... Ts>
constinit auto add_pointer = type_list< decltype(ValueOrVoidPtr(Ts())) ...>{};
template<class... Ts>
constinit auto add_pointer = type_list<decltype([](auto v)
{
if constexpr (requires { v.value; })
{
return v.value;
}
else
{
return;
}
}(std::declval<Ts>()))*...>{};