我编写了一个函数来将函数应用于 std::tuple
如下(基于 "unpacking" a tuple to call a matching function pointer )。
我担心元组可能会被复制。我对 move 语义的作用有一个非常基本的概念,并且理解常见字符串示例中的 && 和右值等概念。但我不太了解 std::forward() 之类的工作原理。当还有打包和可变参数编程时,我不确定如何处理它。 (我在周围添加了一些 std::forward 和 &&,很快就会出现编译错误。)
有人可以在这里解释如何使 move 语义对元组起作用吗?另一个问题是,我如何验证(代码的视觉检查除外) move 语义确实适用于代码中的元组?
提前致谢。
#include <tuple>
#include <iostream>
#include <functional>
template<int ...> struct seq {};
template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {};
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };
template <typename R, typename Tp, typename ...FArgs>
struct t_app_aux {
template<int ...S>
R static callFunc(std::function<R (FArgs...)> f,Tp t,seq<S...>) {
return f(std::get<S>(t) ...);
}
};
template <typename R, typename Tp, typename ...FArgs>
R t_app(std::function<R (FArgs...)> f, Tp t) {
static_assert(std::tuple_size<Tp>::value == sizeof...(FArgs), "type error: t_app wrong arity");
return t_app_aux<R, Tp, FArgs...>::callFunc(f,t,typename gens<sizeof...(FArgs)>::type());
}
int main(void)
{
std::tuple<int, float, double> t = std::make_tuple(1, 1.2, 5);
std::function<double (int,float,double)> foo1 = [](int x, float y, double z) {
return x + y + z;
};
std::cout << t_app(foo1,t) << std::endl;
}
最佳答案
有您当前实现的拷贝:http://ideone.com/cAlorb 我添加了一个带有一些日志的类型:
struct foo
{
foo() : _value(0) { std::cout << "default foo" << std::endl; }
foo(int value) : _value(value) { std::cout << "int foo" << std::endl; }
foo(const foo& other) : _value(other._value) { std::cout << "copy foo" << std::endl; }
foo(foo&& other) : _value(other._value) { std::cout << "move foo" << std::endl; }
int _value;
};
以及申请之前/之后:
std::cout << "Function created" << std::endl;
std::cout << t_app(foo1,t) << std::endl;
std::cout << "Function applied" << std::endl;
它给出:
Function created
copy foo
copy foo
7.2
Function applied
那么,要修复这个添加前向是这样完成的:
template <typename R, typename Tp, typename ...FArgs>
struct t_app_aux {
template<int ...S>
R static callFunc(std::function<R (FArgs...)> f, Tp&& t, seq<S...>) {
return f(std::get<S>(std::forward<Tp>(t)) ...);
}
};
template <typename R, typename Tp, typename ...FArgs>
R t_app(std::function<R (FArgs...)> f, Tp&& t)
{
static_assert(std::tuple_size<typename std::remove_reference<Tp>::type>::value == sizeof...(FArgs),
"type error: t_app wrong arity");
return t_app_aux<R, Tp, FArgs...>::callFunc(f, std::forward<Tp>(t), typename gens<sizeof...(FArgs)>::type());
}
如您所见,它删除了不需要的拷贝:http://ideone.com/S3wF6x
Function created
7.2
Function applied
唯一的问题是处理 static_assert
因为std::tuple_size
被称为 std::tuple<>&
它没有用。我用了typename std::remove_reference<Tp>::type
但也许有一种聪明且更通用的方法?
关于c++ - 如何确保 std::tuple 在以下代码中使用 c++11 move 语义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21252869/