如何在c++ 0x中通过lambda传递

How to pass by lambda in C++0x?

本文关键字:lambda 传递 0x c++      更新时间:2023-10-16

在c++中构造对象避免复制/移动(特别是对于大堆栈分配的对象)的方法似乎是"通过lambda传递"。

请看下面的代码:

#include <iostream>
#define LAMBDA(x) [&] { return x; }
class A
{
public:
  A() {};
  A(const A&) { std::cout << "Copy "; }
  A(A&&) { std::cout << "Move "; }
};
class B1
{
public:
  B1(const A& a_) : a(a_) {}
  B1(A&& a_) : a(std::move(a_)) {}
  A a;
};
class B2
{
public:
  B2(const A& a_) : a(a_) {}
  B2(A&& a_) : a(std::move(a_)) {}
  template <class LAMBDA_T>
  B2(LAMBDA_T&& f, decltype(f())* dummy = 0) : a(f()) {}
  A a;
};
int main()
{
  A a;
  std::cout << "B1 b11(       a ): ";
  B1 b11(a);
  std::cout << std::endl;
  std::cout << "B2 b12(LAMBDA(a)): ";
  B2 b12(LAMBDA(a));
  std::cout << std::endl;
  std::cout << std::endl;
  std::cout << "B1 b21(       std::move(a) ): ";
  B1 b21(std::move(a));
  std::cout << std::endl;
  std::cout << "B2 b22(LAMBDA(std::move(a))): ";
  B2 b22(LAMBDA(std::move(a)));
  std::cout << std::endl;
  std::cout << std::endl;
  std::cout << "B1 b31((       A() )): "; 
  B1 b31((A())); 
  std::cout << std::endl;
  std::cout << "B2 b32((LAMBDA(A()))): ";
  B2 b32((LAMBDA(A()))); 
  std::cout << std::endl;
  std::cout << std::endl;
}

输出如下:

B1 b11(       a ): Copy 
B2 b12(LAMBDA(a)): Copy 
B1 b21(       std::move(a) ): Move 
B2 b22(LAMBDA(std::move(a))): Move 
B1 b31((       A() )): Move 
B2 b32((LAMBDA(A()))): 

注意,如果参数是一个我认为被称为"右值"的值,则"通过lambda传递"会删除移动。

请注意,"通过lambda传递"方法似乎只在参数为"右值"时有用,但在其他情况下似乎没有害处。

在c++ 0x中是否有方法让函数接受"通过lambda传递"参数,这比客户端必须在lambda函数中包装其参数更好?(而不是定义一个调用该函数的代理宏)。

如果您对模板化构造函数没有意见,那么您不妨使用完全转发,而不是使用lambdas来混淆。

class super_expensive_type {
public:
    struct token_t {} static constexpr token = token_t {};
    super_expensive_type(token_t);
}
constexpr super_expensive_type::token_t super_expensive_type::token;
class user {
public:
    template<typename... Args>
    explicit
    user(Args&&... args)
        : member { std::forward<Args>(args)... }
    {}
private:
    super_expensive_type member;
};
// ...
// only one construction here
user { super_expensive_type::token };
super_expensive_type moved_from = ...;
// one move
user { std::move(moved_from) };
super_expensive_type copied_from = ...;
// one copy
user { copied_from };

使用lambda不能比这更好,因为必须返回lambda主体中表达式的结果。

你的做法存在一个根本问题。你不能用魔法使一个物体存在。变量必须是:

  1. 默认构建
  2. 复制构造
  3. 移动构建
  4. 用不同的构造函数构造。

4不在考虑范围内,因为您只定义了前三个。copy和move构造函数都打印东西。因此,可以得出的唯一结论是,如果没有打印任何内容,则对象正在被默认构造。IE:填满nothing.

简而言之,基于lambda的传输机制似乎根本没有传输任何东西。


经过进一步分析,我明白发生了什么。你的lambda实际上并没有通过引用获取值;它是构造一个值。如果展开宏,得到的结果是:

B2 b32(([&] {return A()}));

构造一个临时的;它实际上不需要参考任何东西。所以我不确定你怎么能认为这是"传递"任何东西。你所做的就是创建一个函数来构造一个对象。您可以简单地将B2::a的构造函数的参数传递给B2的构造函数,并让它使用它们来创建对象,并且它会给您相同的效果。

没有传递值。你正在创建一个总是创建完全相同对象的函数。这不是很有用。