如何确定一个std ::函数的参数是多少?(How do I determine the numbe

2019-08-19 10:25发布

我有以下问题。 假设你想要写,可以采取一个lambda表达式的通用功能。 我明白,如果该参数的类型的std ::功能,那么我不仅可以使用lambda表达式,而且功能甚至指向函数的指针。 因此,在第一步,我做了以下内容:

void print(std::function<void(int, int)> fn) {
  fn(1,2);
}

int main() {

  print([](int i, int j) { std::cout << j <<','<<i<<'\n'; });
  return 0;
}

现在的问题是,我想使这个功能一般,这意味着我不希望lambda表达式只有两个参数。 所以,我试图改变打印功能的签名的东西更通用的,如:

template <class function_type>
void print(function_type fn);

但现在的问题是,该功能将任何对象,我没有确定这一点。 但主要问题是,我不知道该对象FN能有多少参数接受。

因此,在某种程度上,我正在寻找一个编译时间的方法来确定多少个参数FN了,如果可以改变类型fn到std ::功能。 然后,因为我知道那FN接受的参数的数量,是有包装的要传递给FN任意数目参数的一个通用的方法是什么? 我甚至不知道这个范围内C ++ 11是可能的。 我的意思是,给定参数的数目,有没有办法收拾参数传递给FN? 所以,如果有两个参数,然后我会打电话

fn(arg1, arg2);

如果有三个:

fn(arg1, arg2, arg3);

等等。

谢谢大家对你的洞察力。

AA

Answer 1:

下面的代码片段可能是有用的。

这给出了争论,一个数std::function需要

template <typename Signature>
struct count_args;

template <typename Ret, typename... Args>
struct count_args<std::function<Ret(Args...)>> {
    static constexpr size_t value = sizeof...(Args);
};

例如,下面的代码编译(铛3.2,GCC 4.7.2和ICC 13.1.0)

static_assert(count_args<std::function<void()        >>::value == 0, "Ops!");
static_assert(count_args<std::function<void(int)     >>::value == 1, "Ops!");
static_assert(count_args<std::function<void(int, int)>>::value == 2, "Ops!");

据我了解,你要调用传递正确的参数个数的函数对象,对不对? 然后为每个参数,我们需要提供一个值,该值转换为它的类型。 这种泛化的解决方案是很难(甚至不可能)。 因此,我会提出了两种备选方案。

1个中的每个参数是它的类型的值初始化的对象。 (这是ecatmur 建议 。)

template <typename Ret, typename... Args>
Ret call(const std::function<Ret(Args...)>& f) {
    return f(Args{}...); // for the intel compiler replace {} with ()
}

2所述的固定值,并给出所有参数被隐式地从该值初始化:

template <typename Ret, typename... Args, typename Val, typename... Vals>
typename std::enable_if<sizeof...(Args) == sizeof...(Vals), Ret>::type
call(const std::function<Ret(Args...)>& f, const Val&, const Vals&... vals) {
    return f(vals...);
}

template <typename Ret, typename... Args, typename Val, typename... Vals>
typename std::enable_if<(sizeof...(Args) > sizeof...(Vals)), Ret>::type
call(const std::function<Ret(Args...)>& f, const Val& val, const Vals&... vals) {
    return call(f, val, val, vals...);
}

的三个重载是明确的,并且可以被用作下列实施例显示:

{
    std::function<char()> f = []() -> char {
        std::cout << "f() ";
        return 'A';
    };
    std::cout << call(f)    << std::endl; // calls f()
    std::cout << call(f, 0) << std::endl; // calls f()
}
{
    std::function<char(int)> f = [](int i) -> char {
        std::cout << "f(" << i << ") ";
        return 'B';
    };
    std::cout << call(f)    << std::endl; // calls f(0)
    std::cout << call(f, 1) << std::endl; // calls f(1)
}
{
    std::function<char(int, int)> f = [](int i, int j) -> char {
        std::cout << "f(" << i << "," << j << ") ";
        return 'C';
    };
    std::cout << call(f)    << std::endl; // calls f(0, 0)
    std::cout << call(f, 2) << std::endl; // calls f(2, 2)
}


Answer 2:

是的,你可以装许多参数fn ,你想使用可变参数模板。

template <class function_type, class... Args>
void print(function_type fn, Args... args)
{
    //Call fn with args
    fn(std::forward<Args>(args...));
}

要找出多少ARGS有在参数包,你可以使用sizeof...(args)



Answer 3:

要确定一个可调用的签名,你可以从使用该解决方案推断拉姆达或任意调用为“make_function”的调用签名 。 然后,您可以打包成可调用一个std::function ,或创建一个标签和使用参数推断:

template<typename T> struct tag {};

template<typename F, typename... Args>
void print_impl(F &&fn, tag<void(Args...)>) {
  fn(Args{}...);
}

template<typename F>
void print(F &&fn) {
  print_impl(std::forward<F>(fn), tag<get_signature<F>>{});
}

注意:此使用值初始化参数; 如果你想什么更复杂的,你可以建立一个std::tuple<Args...>和传递下去,调用它每次“拆包”的元组调用匹配函数指针 。



文章来源: How do I determine the number of parameters of a std::function?