c ++ 11:使用向量的元素调用可变参数函数,并自动推导参数数量
c++11: Calling a variadic function with the elements of a vector, and deduce number of arguments automatically
尝试扩展此处找到的示例:
基本上,我想从自动传入的函数中推断出参数的数量(这显然不适用于重载函数)。我希望它也能与仿函数和 lambda 一起使用。
无法编译对 call_helper
的调用:错误:模板参数解析错误
我似乎无法弄清楚如何将 returns 参数数量作为模板参数传递给 constexpr。
这是我目前拥有的:
#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);
}
我错过了什么或做错了什么?感谢任何帮助。
编辑:添加了仿函数和 lambda 用例
有两个错误:
- 在
call_helper<get_args_count(decltype(f))>(f, args)
中,get_args_count(decltype(f))
没有意义,因为 get_args_count
采用函数指针而不是类型(显然);
- 函数参数永远不能是 constexpr(我会让你搜索为什么)。
如何修复?
您需要尽快提取 f
的参数数量,以免它变成在 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 的答案解决了常规函数的问题,但不适用于 lambda 和仿函数。为了使其也适用于仿函数和 lambda,我必须添加 call
的重载(基于 中的解决方案):
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);
}
尝试扩展此处找到的示例:
基本上,我想从自动传入的函数中推断出参数的数量(这显然不适用于重载函数)。我希望它也能与仿函数和 lambda 一起使用。
无法编译对 call_helper
的调用:错误:模板参数解析错误
我似乎无法弄清楚如何将 returns 参数数量作为模板参数传递给 constexpr。
这是我目前拥有的:
#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);
}
我错过了什么或做错了什么?感谢任何帮助。
编辑:添加了仿函数和 lambda 用例
有两个错误:
- 在
call_helper<get_args_count(decltype(f))>(f, args)
中,get_args_count(decltype(f))
没有意义,因为get_args_count
采用函数指针而不是类型(显然); - 函数参数永远不能是 constexpr(我会让你搜索为什么)。
如何修复?
您需要尽快提取 f
的参数数量,以免它变成在 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 的答案解决了常规函数的问题,但不适用于 lambda 和仿函数。为了使其也适用于仿函数和 lambda,我必须添加 call
的重载(基于 中的解决方案):
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);
}