在C ++ 0x中避免移动/复制的更好方法

时间:2011-07-14 11:51:53

标签: c++ c++11 copy-elision

这个问题来自How to pass by lambda in C++0x?,但也许这是一个更清楚的问题提问方式。

考虑以下code

#include <iostream>

#define LAMBDA(x) [&] { return x; }

class A
{
public:
  A() : i(42) {};
  A(const A& a) : i(a.i) { std::cout << "Copy " << std::endl; }
  A(A&& a) : i(a.i) { std::cout << "Move " << std::endl; }
  int i;
};

template <class T>
class B
{
public:
  B(const T& x_) : x(x_) {}
  B(T&& x_) : x(std::move(x_)) {}
  template <class LAMBDA_T>
  B(LAMBDA_T&& f, decltype(f())* dummy = 0) : x(f()) {}
  T x;
};

template <class T>
auto make_b_normal(T&& x) -> B<typename std::remove_const<typename std::remove_reference<T>::type>::type>
{
  return B<typename std::remove_const<typename std::remove_reference<T>::type>::type>(std::forward<T>(x));
}

template <class LAMBDA_T>
auto make_b_macro_f(LAMBDA_T&& f) -> B<decltype(f())>
{
  return B<decltype(f())>( std::forward<LAMBDA_T>(f) );
}

#define MAKE_B_MACRO(x) make_b_macro_f(LAMBDA(x))

int main()
{
  std::cout << "Using standard function call" << std::endl;
  auto y1 = make_b_normal(make_b_normal(make_b_normal(make_b_normal(A()))));
  std::cout << "Using macro" << std::endl;
  auto y2 = MAKE_B_MACRO(MAKE_B_MACRO(MAKE_B_MACRO(MAKE_B_MACRO(A()))));
  std::cout << "End" << std::endl;
}

其中输出以下内容:

Using standard function call
Move 
Copy 
Copy 
Copy 
Using macro
End

很明显,宏版本以某种方式省略了所有移动/复制构造函数调用,但函数版本没有。

我认为在C ++ 0x中有一种语法上很好的方法可以省略所有的动作和副本而没有很多宏,但是我无法理解它。

原因:

我计划在没有移动或副本的情况下使用此类代码来构建参数包,即

auto y = (_blah = "hello", _blah2 = 4);
f(y, (_blah3 = "world", _blah4 = 67));

与非参数代码相比,这些没有额外的动作/副本。

1 个答案:

答案 0 :(得分:1)

您未能为B提供移动构造函数。提供时,然后在Visual Studio 2010上我得到一堆动作。它不会消除任何移动的原因是因为您创建了B<B<B<B<A>>>>

编译器仍然非常不成熟w.r.t.移动椭圆。我希望他们以后会好起来的。