Info
-
Did you know that Circle Meta-model allows for applying
normal
STL for operations on @meta types?
Example
int main() {
@meta std::array types{@dynamic_type(int), @dynamic_type(bool)};
((std::cout << @type_string(@pack_type(types)) << ' '), ...); // int bool
}
Puzzle
- Can you implement
rotate_types
andcalls_verify_types
by applying STL with @meta types?
template<auto N, class... Ts>
constexpr auto rotate_types(); // TODO
constexpr auto calls_verify_types(auto expected, auto given); // TODO
int main() {
using namespace boost::ut;
"rotate types"_test = [] {
should("not change the input on empty list") = [] {
expect(std::is_same_v<list<>, decltype(rotate_types<0>())>);
static_assert(not []<class T>(T) { return requires { rotate_types<T::value>(); }; }(std::integral_constant<int, 1>{}));
};
should("return the same input with 1 element") = [] {
expect(std::is_same_v<list<int>, decltype(rotate_types<0, int>())>);
expect(std::is_same_v<list<int>, decltype(rotate_types<1, int>())>);
static_assert(not []<class T>(T) { return requires { rotate_types<T::value, int>(); }; }(std::integral_constant<int, 2>{}));
};
should("rotate rigth input with multiple elements") = [] {
expect(std::is_same_v<list<double, int, float>, decltype(rotate_types<0, double, int, float>())>);
expect(std::is_same_v<list<int, float, double>, decltype(rotate_types<1, double, int, float>())>);
expect(std::is_same_v<list<float, double, int>, decltype(rotate_types<2, double, int, float>())>);
expect(std::is_same_v<list<double, int, float>, decltype(rotate_types<3, double, int, float>())>);
static_assert([]<class T>(T) { return requires { rotate_types<T::value, double, int, float>(); }; }(std::integral_constant<int, 0>{}));
static_assert([]<class T>(T) { return requires { rotate_types<T::value, double, int, float>(); }; }(std::integral_constant<int, 1>{}));
static_assert(not []<class T>(T) { return requires { rotate_types<T::value, double, int, float>(); }; }(std::integral_constant<int, 4>{}));
static_assert(not []<class T>(T) { return requires { rotate_types<T::value, double, int, float>(); }; }(std::integral_constant<int, 5>{}));
};
should("allow to unpack rotated types") = [] {
constexpr auto expected = []<class T>(T){static_assert(std::is_same_v<list<float, double, int>, T>);};
constexpr auto given = rotate_types<2, double, int, float>();
calls_verify_types(expected, given);
};
};
}
Solutions
template<auto N, class... Ts> requires ( N <= sizeof...(Ts))
constexpr auto rotate_types()
{
if constexpr ( sizeof...(Ts) <= 1)
return list<Ts...>{};
else
{
@meta std::array types{@dynamic_type(Ts)...};
@meta std::rotate(types.begin(), types.begin() + N, types.end());
return list<@pack_type(types)...>{};
}
}
constexpr auto calls_verify_types(auto expected, auto given)
{
expected(given);
}
template <auto N, class... Ts> requires (N <= sizeof...(Ts))
constexpr auto rotate_types() {
if constexpr (sizeof...(Ts) <= 1) {
return list<Ts...>{};
} else {
@meta std::array types{@dynamic_type(Ts)...};
@meta std::rotate(std::begin(types), std::next(std::begin(types), N), std::end(types));
return list<@pack_type(types)...>{};
}
}
constexpr auto calls_verify_types(auto expected, auto given) -> decltype(auto) {
return expected(given);
}
template<auto N, class... Ts>
requires (N <= sizeof...(Ts))
constexpr auto rotate_types() {
if constexpr (sizeof...(Ts) <= 1) {
return list<Ts...>{};
} else {
@meta auto types = std::array{@dynamic_type(Ts)...};
@meta std::rotate(std::begin(types), std::next(std::begin(types), N), std::end(types));
return list<@pack_type(types)...>{};
}
}
constexpr auto calls_verify_types(auto expected, auto given) {
return expected(given);
}
template<auto N, class... Ts>
requires (N <= sizeof...(Ts))
constexpr auto rotate_types() {
if constexpr (sizeof...(Ts) <= 1) {
return list<Ts...>{};
} else {
@meta auto types = std::array{@dynamic_type(Ts)...};
@meta std::rotate(std::begin(types), std::next(std::begin(types), N), std::end(types));
return list<@pack_type(types)...>{};
}
}
constexpr auto calls_verify_types(auto expected, auto given) {
return expected(given);
}
template<auto N, class... Ts>
constexpr auto rotate_types() requires (N <= sizeof...(Ts)) {
if constexpr (sizeof...(Ts) == 0) {
return list{};
} else {
@meta std::array types{@dynamic_type(Ts)...};
@meta std::rotate(types.begin(), types.begin() + N, types.end());
return list<@pack_type(types)...>{};
}
}
template <class... Ts>
constexpr auto calls_verify_types(auto expected, list<Ts...> given) {
return verify_types<Ts...>(expected);
}
template<auto N, class... Ts>
constexpr auto rotate_types() requires (N <= sizeof...(Ts)) {
if constexpr (sizeof...(Ts) > 0) {
@meta std::array types{@dynamic_type(@member_types(list<Ts...>))...};
@meta std::rotate(std::begin(types), std::begin(types) + N, std::end(types));
return list<@pack_type(types)...>{};
} else {
return list{};
}
}
constexpr auto calls_verify_types(auto expected, auto given) {
verify_types<@member_types(decltype(given))...>(expected);
}