一个向量/映射中的std :: function变量参数

时间:2015-08-10 12:42:54

标签: c++ c++11 c++14 std-function

今天如何在不使用两个单独的持有者的情况下在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函数以包含不同的参数集吗? 这可以通过现在的变量模板或类似的东西来解决吗?

2 个答案:

答案 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)) );
}

live example