c++ - 如何确保 std::tuple 在以下代码中使用 c++11 move 语义

标签 c++ c++11 variadic-templates move-semantics

我编写了一个函数来将函数应用于 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/

相关文章:

c++ - 使用可变模板参数传递成员函数指针是不明确的

c++ - VS2017 是否完全支持折叠表达式?

c++ - 关键部分所有权

c++ - 哪种设计模式适合这种情况?

c++ - 如何解析成员指针非类型模板参数的组件类型

c++ - C++中<<运算符重载函数的返回类型

c++ - 如何使用可变参数模板打印出函数的参数?

c++ - 模仿 socket.h (C++) 的 OpenSSL 包装器

c++ - 计算相邻盒子的数量

c++ - 智能指针+循环+ "->"