std::function 可变参数合一 vector/map
std::function variable arguments in one vector/map
如果不使用两个单独的支架,今天如何在 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 函数以包含不同的参数集?
现在可以通过可变模板或类似的东西解决这个问题吗?
创建一个与新签名匹配的新 lambda 并改为添加:
void add(f2 f)
{
m.push_back( [g = std::move(f)](int a, int /* unused */){ g(a); } );
}
这将 std::function
包装在忽略任何额外参数的 lambda 中:
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)...);
};
}
如果我们不想要那种不必要的类型擦除层,它会变得更加棘手。
您需要找到可以调用给定对象 f
的 Args...
的最长前缀,然后用它调用 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)) );
}
如果不使用两个单独的支架,今天如何在 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 函数以包含不同的参数集? 现在可以通过可变模板或类似的东西解决这个问题吗?
创建一个与新签名匹配的新 lambda 并改为添加:
void add(f2 f)
{
m.push_back( [g = std::move(f)](int a, int /* unused */){ g(a); } );
}
这将 std::function
包装在忽略任何额外参数的 lambda 中:
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)...);
};
}
如果我们不想要那种不必要的类型擦除层,它会变得更加棘手。
您需要找到可以调用给定对象 f
的 Args...
的最长前缀,然后用它调用 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)) );
}