I needed a runtime visitor analogue to meta::for_each:
using List = meta::list<int,double,float,double>;
std::size_t index = 2
meta::visit<List>(2, [](auto type){ std::cout << "called with type==double"; });
I came up with this, which builds a static function pointer map:
namespace meta
{
namespace details
{
template<typename Func, typename Type>
struct Wrapper
{
static void invoke(Func f) { f(Type{}); }
};
template<typename Func, typename List> struct visit;
template<typename Func, typename... Types>
struct visit<Func, meta::list<Types...>>
{
static constexpr auto makeMap()
{
using FuncPtr = decltype(&Wrapper<Func, void>::invoke);
using Array = std::array<FuncPtr, sizeof...(Types)>;
// Build member function pointers.
return Array{&Wrapper<Func, Types>::invoke...};
}
};
} // namespace details
//! Apply the function `Func` with the type
//! in the `List` at position `index`.
template<typename List, typename Func>
void visit(std::size_t index, Func&& f)
{
using F = decltype(std::forward<Func>(f)); // Define either an lvalue, or rvalue;
constexpr auto map = details::visit<F, List>::makeMap();
if(index >= map.size()){ throw std::out_of_range();}
map[index](std::forward<Func>(f));
}
} // namespace meta
Works like a charm for example with an rvalue lambda:
MY_TEST(MetaProgramming, Test1)
{
using List = meta::list<int, double, short>;
int b = -1;
meta::visit<List>(2,
[&](auto type) {
using T = decltype(type);
if constexpr(std::is_same<T, short>{})
{
b = 2;
}
});
ASSERT_EQ(b, 2) << "Meta Visit failed!";
}
I needed a runtime visitor analogue to
meta::for_each
:I came up with this, which builds a static function pointer map:
Works like a charm for example with an rvalue lambda: