今天如何在不使用两个单独的持有者的情况下在c ++中做到这一点?
typedef std::function<void(int a, int b)> f1;
typedef std::function<void(int a)> f2;
std::vector<f1> m;
void add(f1 f)
{
m.push_back(f);
}
void add(f2 f)
{
// add one more (unused) parameter to f2 so we can add f2 to f1 vector holder?
}
我们可以以某种方式重载f1函数以包含不同的参数集吗? 这可以通过现在的变量模板或类似的东西来解决吗?
答案 0 :(得分:6)
创建一个与新签名匹配的新lambda,并添加它:
void add(f2 f)
{
m.push_back( [g = std::move(f)](int a, int /* unused */){ g(a); } );
}
答案 1 :(得分:0)
这将std::function
包裹在lambda中,忽略任何额外的args:
template<class R, class...Args>
auto ignore_extra_args( std::function<R(Args...)> f ) {
return [f = std::move(f)](Args...args, auto&&...)->R{
return f(std::forward<Args>(args)...);
};
}
如果我们不想要那种不必要的类型擦除,它会变得更加棘手。
您需要找到Args...
的最长前缀,您可以使用它来调用给定对象f
,然后使用它调用f
。这涉及一些棘手的元编程。
如果要求来电者传递签名,那就容易多了:
template<class Sig>
struct ignore_extra_args_helper;
template<class R, class...Args>
struct ignore_extra_args_helper<R(Args...)> {
template<class F>
auto operator()( F&& f ) {
return [f = std::forward<F>(f)](Args...args, auto&&...)->R{
return f(std::forward<Args>(args)...);
};
}
};
template<class Sig, class F>
auto ignore_extra_args( F&& f ) {
return ignore_extra_args_helper<Sig>{}(std::forward<F>(f));
}
节省了可能的开销。
template<class F, decltype(std::declval<F const&>()(1,1))* =nullptr>
void add(F&& f) {
m.push_back(std::forward<F>(f));
}
template<class F, class...Unused>
void add(F&& f, Unused&&...) {
add( ignore_extra_args<void(int)>(std::forward<F>(f)) );
}