C++ 如何将参数的::std::vector绑定到函子?
我正在努力使该程序正确编译:C++ 如何将参数的::std::vector绑定到函子?,c++,templates,c++11,C++,Templates,C++11,我正在努力使该程序正确编译: #include <vector> #include <iostream> int f(int a, int b) { ::std::cout << "f(" << a << ", " << b << ") == " << (a + b) << '\n'; return a + b; } template <typename R, typ
#include <vector>
#include <iostream>
int f(int a, int b)
{
::std::cout << "f(" << a << ", " << b << ") == " << (a + b) << '\n';
return a + b;
}
template <typename R, typename V>
R bind_vec(R (*f)(), const V &vec, int idx=0)
{
return f();
}
template <typename R, typename V, typename Arg1, typename... ArgT>
R bind_vec(R (*f)(Arg1, ArgT...), const V &vec, int idx=0)
{
const Arg1 &arg = vec[idx];
auto call = [arg, f](ArgT... args) -> R {
return (*f)(arg, args...);
};
return bind_vec(call, vec, idx+1);
}
int foo()
{
::std::vector<int> x = {1, 2};
return bind_vec(f, x);
}
#包括
#包括
int f(int a,int b)
{
::std::cout好的,首先,可以检测函子的arity,但这有点复杂,最好留给一个单独的问题。让我们假设您将在调用中指定函子的arity。类似地,也有方法获取可调用对象的返回类型,但这也超出了这个问题的范围。让我们假设目前返回类型为void
所以我们想说,
call(F f, C v);
也就是说,f(v[0],v[1],…,v[n-1])
,其中f
具有arityn
以下是一种方法:
template <unsigned int N, typename Functor, typename Container>
void call(Functor const & f, Container const & c)
{
call_helper<N == 0, Functor, Container, N>::engage(f, c);
}
模板
void调用(函子常量&f,容器常量&c)
{
呼叫助手::啮合(f,c);
}
我们需要助手:
#include <functional>
#include <cassert>
template <bool Done, typename Functor, typename Container,
unsigned int N, unsigned int ...I>
struct call_helper
{
static void engage(Functor const & f, Container const & c)
{
call_helper<sizeof...(I) + 1 == N, Functor, Container,
N, I..., sizeof...(I)>::engage(f, c);
}
};
template <typename Functor, typename Container,
unsigned int N, unsigned int ...I>
struct call_helper<true, Functor, Container, N, I...>
{
static void engage(Functor const & f, Container const & c)
{
assert(c.size() >= N);
f(c[I]...);
}
};
#包括
#包括
模板
结构调用辅助程序
{
静态无效接合(函子常数&f、容器常数&c)
{
呼叫助手::啮合(f,c);
}
};
模板
结构调用辅助程序
{
静态无效接合(函子常数&f、容器常数&c)
{
断言(c.size()>=N);
f(c[I]…);
}
};
示例:
#include <vector>
#include <iostream>
void f(int a, int b) { std::cout << "You said: " << a << ", " << b << "\n"; }
struct Func
{
void operator()(int a, int b) const
{ std::cout << "Functor: " << a << "::" << b << "\n"; }
};
int main()
{
std::vector<int> v { 20, 30 };
call<2>(f, v);
call<2>(Func(), v);
}
#包括
#包括
void f(inta,intb){std::cout我成功地实现了您想要的功能。如果一开始我没有推导正确的返回类型,最简单的解释是,我将在后面演示如何添加它:
#include <vector>
#include <type_traits>
namespace {
int f(int a, int b) { return 0; }
}
template <typename ...Args>
constexpr unsigned nb_args(int (*)(Args...)) {
return sizeof...(Args);
}
template <typename F, typename V, typename ...Args>
auto bind_vec(F f, const V&, Args&& ...args)
-> typename std::enable_if<sizeof...(Args) == nb_args(F()),void>::type
{
f(std::forward<Args>(args)...);
}
template <typename F, typename V, typename ...Args>
auto bind_vec(F f, const V& v, Args&& ...args)
-> typename std::enable_if<sizeof...(Args) < nb_args(F()),void>::type
{
bind_vec(f, v, std::forward<Args>(args)..., v.at(sizeof...(Args)));
}
int main() {
bind_vec(&f, std::vector<int>(), 1);
return 0;
}
对于(成员)函数指针来说,这样做很容易,但是对于可能重载了操作符()
的函子来说,这会变得困难得多。如果我们假设您有办法知道一个函数需要多少参数(并假设容器实际有那么多元素),您可以使用将向量展开为参数列表,例如使用std::next
和begin()
迭代器:
#include <utility>
#include <iterator>
template<class F, class Args, unsigned... Is>
auto invoke(F&& f, Args& cont, seq<Is...>)
-> decltype(std::forward<F>(f)(*std::next(cont.begin(), Is)...))
{
return std::forward<F>(f)(*std::next(cont.begin(), Is)...);
}
template<unsigned ArgC, class F, class Args>
auto invoke(F&& f, Args& cont)
-> decltype(invoke(std::forward<F>(f), cont, gen_seq<ArgC>{}))
{
return invoke(std::forward<F>(f), cont, gen_seq<ArgC>{});
}
请注意,您甚至不需要使用function\u-arity
使invoke
从上面为std::function
工作:
template<class R, class... Ts, class Args>
R invoke(std::function<R(Ts...)> const& f, Args& cont){
return invoke_1(f, cont, gen_seq<sizeof...(Ts)>{})
}
模板
R调用(std::函数const&f、Args&cont){
返回invoke_1(f,cont,gen_seq{})
}
我们可以简化这一点吗:您想要一个小工具,通过使用容器的前n个元素调用任意容器中的n个参数的函数来调用该函数吗?@KerrekSB:是的。但它必须是一个在运行时填充了元素的容器。最好它可以调用任何实现的操作符()
@Xeo:哦,我想它实际上并不涉及正常意义上的咖喱。:-)这对带有操作符()
的函子对象也有效吗?@KerrekSB-对nb_args()
会有适当的重载。@flex:祝你创建一个-操作符()好运)
可以重载。有了函数指针,用户在将其传递给函数之前就必须消除歧义。@Flexo:在这种情况下,我真的很担心,我可以指望函子是::std::function
@Omnifarious:这很容易,你为什么不在问题中这么说?这显然适用于函子。如果没有你提到的算术计算,现在还不清楚如何扩展函子的另一个。我最终使用的方法与此最接近。但是@Xeo的答案也很好。我会+1这个,除了我不认为我能理解它的工作原理之外。-@Omnifarious:Whe问题到底出在哪里?对于索引技巧,我链接了lounge wiki,使用它有很多答案。对于其他问题,只要提问,我会尽力解释(更好)@Xeo:我想我缺少的是理解索引技巧。我会仔细阅读你发布的链接。gen_seq
的定义是什么?哦!我明白了。它生成索引。嗯……还有ArgC,那必须手工提供吗?@Omnifarious:正如我所说,我在这篇文章中假设你有办法获得实际的参数函数(对象)应使用调用。对于std::function
,很容易获取。添加了代码。
#include <utility>
template<class T> using Alias = T; // for temporary arrays
template<class F, class It, unsigned N, unsigned... Is>
auto invoke_2(F&& f, It (&&args)[N], seq<Is...>)
-> decltype(std::forward<F>(f)(*args[Is]...))
{
return std::forward<F>(f)(*args[Is]...);
}
template<class F, class Args, unsigned... Is>
auto invoke_1(F&& f, Args& cont, seq<Is...> s)
-> decltype(invoke_2(std::forward<F>(f), std::declval<decltype(cont.begin())[sizeof...(Is)]>(), s))
{
auto it = cont.begin();
return invoke_2(std::forward<F>(f), Alias<decltype(it)[]>{(void(Is), ++it)...}, s);
}
template<unsigned ArgC, class F, class Args>
auto invoke(F&& f, Args& cont)
-> decltype(invoke_1(std::forward<F>(f), cont, gen_seq<ArgC>{}))
{
return invoke_1(std::forward<F>(f), cont, gen_seq<ArgC>{});
}
template<class F> struct function_arity;
// if you have the 'Signature' of a 'std::function' handy
template<class R, class... Args>
struct function_arity<R(Args...)>
: std::integral_constant<std::size_t, sizeof...(Args)>{};
// if you only have the 'std::function' available
template<class R, class... Args>
struct function_arity<std::function<R(Args...)>>
: function_arity<R(Args...)>{};
template<class R, class... Ts, class Args>
R invoke(std::function<R(Ts...)> const& f, Args& cont){
return invoke_1(f, cont, gen_seq<sizeof...(Ts)>{})
}