我有一个带有许多函子的std::tuple
,该函子使用不同的参数实现回调。我想在编译时遍历元组并执行与参数兼容的函子:
假设我有一组函子:
struct functor_a { void operator()(const class_x&) {} };
struct functor_b { void operator()(const class_x&) {} void operator()(const class_y&) {} };
struct functor_c { void operator()(const class_x&) {} void operator()(const class_z&) {} };
给出一个包含它们的元组:
using tuple_type = std::tuple<function_a, function_b, function_c>;
我想做类似的事情:
struct executor {
template<typename message_type, typename... Type>
static constexpr void exec(std::tuple<Types...>& tup, const message_type& msg) {
exec(std::index_sequence_for<Types...>(), tup. msg);
}
template<typename message_type, std::size_t... Is>
static void exec(std::index_sequence<Is...>, tuple_type& tup, const message_type& msg) {
if constexpr (std::is_nothrow_invocable_v<typename std::tuple_element<Is, tuple_type>::type..., message_type>) {
std::invoke(std::get<Is>(tup)..., msg);
}
}
}
};
为了执行此操作(或使用std :: invoke):
auto tup = get_tuple();
executor::exec(tup, class_x()); // Call functor a, b, c
executor::exec(tup, class_y()); // Call functor b
executor::exec(tup, class_z()); // Call functor c
我的constexpr条件一直存在一些问题,该条件始终被评估为true,并且代码无法编译,因为它找不到具有给定参数的运算符:
std::is_nothrow_invocable_v<typename std::tuple_element<Is, tuple_type>::type..., message_type>
您不再需要SFINAE了,实际上只需要一个简单的if constexpr
:
#include <tuple>
#include <string>
struct A {
void operator()(int) const;
};
struct B {
void operator()(std::string) const;
};
struct C {
void operator()(int) const;
void operator()(std::string) const;
};
template<typename FuncT, typename ArgT>
void dispatch_if_possible(const FuncT& f, const ArgT& a ) {
if constexpr(std::is_invocable_v<FuncT, ArgT>) {
f(a);
}
}
template<std::size_t I=0, typename ArgT, typename... Ts>
void dispatch(const std::tuple<Ts...>& tup, const ArgT& arg) {
dispatch_if_possible(std::get<I>(tup), arg);
if constexpr( I+1 < sizeof...(Ts)) {
dispatch<I+1>(tup, arg);
}
}
void foo() {
std::tuple<A, B, C> x;
dispatch(x, 2);
}
void bar() {
std::tuple<A, B, C> x;
dispatch(x, "hello");
}
您可以看到正确的调度here, on godbolt