简体   繁体   English

c++11:用向量的元素调用可变参数函数,并自动推导出参数的数量

[英]c++11: Calling a variadic function with the elements of a vector, and deduce number of arguments automatically

Trying to expand on the example found here: https://stackoverflow.com/a/17974752尝试扩展此处找到的示例: https : //stackoverflow.com/a/17974752

Basically, I'd like to deduce the number of arguments from the function passed in automatically (which obviously wouldn't work for overloaded functions).基本上,我想从自动传入的函数中推断出参数的数量(这显然不适用于重载函数)。 I'd like this to also work with functors and lambdas.我希望这也适用于函子和 lambda。

It's failing to compile the call to call_helper : error: parse error in template argument无法编译对call_helper的调用:错误:模板参数中的解析错误

I can't seem to figure out how to pass in the constexpr that returns the number of arguments as a template argument.我似乎无法弄清楚如何传入返回参数数量作为模板参数的 constexpr。

This is what I have so far:这是我到目前为止:

#include <vector>

template <typename R, typename ... T>
constexpr std::size_t get_args_count( R(*f)(T ...))
{
   return sizeof...(T);
}

template< std::size_t... Ns >
struct indices {
    typedef indices< Ns..., sizeof...( Ns ) > next;
};

template< std::size_t N >
struct make_indices {
    typedef typename make_indices< N - 1 >::type::next type;
};

template<>
struct make_indices< 0 > {
    typedef indices<> type;
};

void abc(int) {}
void abc2(int, int) {}

// helper function because we need a way
// to deduce indices pack

template<typename Func, size_t... Is>
void call_helper2(Func f, const std::vector<int>& args, indices<Is...>)
{
    f( args[Is]... ); // expand the indices pack
}

template<typename Func, size_t N>
void call_helper(Func f, const std::vector<int>& args)
{
    call_helper2(f, args, typename make_indices<N>::type());
}

template<typename Func>
void call(Func f, const std::vector<int>& args)
{
    if (args.size() < get_args_count(f)) throw 42;
    call_helper<get_args_count(decltype(f))>(f, args); // error: parse error in template argument list
}

int main()
{
    struct F
    {
        void operator()(int, int, int, int) {}
    };

    std::vector<int> v(4);
    call(&abc2, v);
    call(&abc, v);
    call([&](int, int, int) { (void)v.empty(); }, v);
    call(F(), v);
}

What am I missing or doing wrong?我错过了什么或做错了什么? Any help is appreciated.任何帮助表示赞赏。

EDIT: Added functor and lambda use cases编辑:添加了函子和 lambda 用例

There was two mistakes:有两个错误:

  1. In call_helper<get_args_count(decltype(f))>(f, args) , get_args_count(decltype(f)) is meaningless as get_args_count takes a function pointer and not a type (obviously);call_helper<get_args_count(decltype(f))>(f, args)get_args_count(decltype(f))是没有意义的,因为get_args_count需要一个函数指针而不是一个类型(显然);
  2. A function argument can never be constexpr (I'll let you search on SO why).函数参数永远不能是 constexpr(我会让你搜索 SO 为什么)。

How to fix?怎么修?

You need to extract the number of arguments of f as soon as possible, before it becomes something else than an expression usable in constexpr context.您需要尽快提取f的参数数量, constexpr它变成可在constexpr上下文中使用的表达式。

#include <vector>

template< std::size_t... Ns >
struct indices {
    typedef indices< Ns..., sizeof...( Ns ) > next;
};

template< std::size_t N >
struct make_indices {
    typedef typename make_indices< N - 1 >::type::next type;
};

template<>
struct make_indices< 0 > {
    typedef indices<> type;
};

void abc(int) {}
void abc2(int, int) {}

// helper function because we need a way
// to deduce indices pack

template<typename Func, size_t... Is>
void call_helper2(Func f, const std::vector<int>& args, indices<Is...>)
{
    f( args[Is]... ); // expand the indices pack
}

template<typename Func, size_t N>
void call_helper(Func f, const std::vector<int>& args)
{
    call_helper2(f, args, typename make_indices<N>::type());
}

template<class R, class ... T>
void call(R(*f)(T ...), const std::vector<int>& args)
{
    if (args.size() < sizeof...(T)) throw 42;
    call_helper<
        decltype(f), sizeof...(T)
    >(f, args);
}

int main()
{
    std::vector<int> v(2);
    call(&abc2, v);
}

YSC's answer solves the problem for regular functions, but it doesn't work with lambdas and functors. YSC 的答案解决了常规函数的问题,但它不适用于 lambda 和函子。 To make this work with functors and lambdas as well, I had to add an overload of call (based on the solution in https://stackoverflow.com/a/7943765/1403469 ):为了使这个函数也适用于函子和 lambda,我必须添加call重载(基于https://stackoverflow.com/a/7943765/1403469 中的解决方案):

template< std::size_t... Ns >
struct indices {
    typedef indices< Ns..., sizeof...( Ns ) > next;
};

template< std::size_t N >
struct make_indices {
    typedef typename make_indices< N - 1 >::type::next type;
};

template<>
struct make_indices< 0 > {
    typedef indices<> type;
};

void abc(int) {}
void abc2(int, int) {}

// helper function because we need a way
// to deduce indices pack

template<typename Func, size_t... Is>
void call_helper2(Func f, const std::vector<int>& args, indices<Is...>)
{
    f( args[Is]... ); // expand the indices pack
}

template<typename Func, size_t N>
void call_helper(Func f, const std::vector<int>& args)
{
    call_helper2(f, args, typename make_indices<N>::type());
}

template<class R, class ... T>
void call(R(*f)(T ...), const std::vector<int>& args)
{
    // this overload is used for regular functions
    if (args.size() < sizeof...(T)) throw 42;
    call_helper<decltype(f), sizeof...(T)>(f, args);
}

template <typename T>
struct func_traits:
    public func_traits<decltype(&T::operator())>
{};

template <typename C, typename R, typename... Args>
struct func_traits<R(C::*)(Args...) const>
{
    enum { arity = sizeof...(Args) };
};

template<typename Func>
void call(Func f, const std::vector<int>& args)
{
    // this overload is used for functors and lambdas
    using traits = func_traits<decltype(f)>;
    if (args.size() < traits::arity) throw 42;
    call_helper<decltype(f), traits::arity>(f, args);
}

int main()
{
    struct F
    {
        void operator()(int, int, int, int) const {}
    };

    std::vector<int> v(4);
    call(&abc2, v);
    call(&abc, v);
    call([&](int, int, int) { (void)v.empty(); }, v);
    call(F(), v);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM