似乎在C ++ 0x中构造对象的方法是避免复制/移动(特别是对于大堆栈分配的对象)是“通过lambda传递”。
请参阅以下code:
#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”会移除参数是我认为称为“prvalue”的情况下的移动。
请注意,似乎“传递lambda”方法仅在参数为“prvalue”时才有用,但在其他情况下似乎没有受到伤害。
有没有让函数接受C ++ 0x中的“传递lambda”参数,这比客户端必须在lambda函数中包装它们的参数更好? (除了定义调用该函数的代理宏之外)。
答案 0 :(得分:3)
如果您对模板化构造函数没有问题,那么您最好使用完美转发而不是使用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 };
使用lambdas不能比这更好,因为必须返回lambda体中表达式的结果。
答案 1 :(得分:2)
你正在做的事情存在根本问题。你不能魔法一个物体存在。变量必须是:
4不在桌面上。你的副本和移动构造函数都打印东西。因此,可以得出的唯一结论是,如果没有打印任何内容,则该对象是默认构造的。 IE:填充没有。
简而言之,基于Lambda的传输机制似乎根本没有转移任何东西。
经过进一步分析,我看到发生了什么。你的lambda实际上并没有通过引用获取值;它是构建一个值。如果你展开宏,你得到的是:
B2 b32(([&] {return A()}));
构建一个临时的;它实际上没有任何参考。所以我不确定你怎么能认为这会“传递”任何东西。你所做的只是制作一个构造一个对象的函数。您可以轻松地将B2::a
的构造函数的参数传递给B2
的构造函数,并让它使用它们来创建对象,它会给您带来相同的效果。
你没有传递一个值。您正在创建一个始终创建完全相同对象的函数。这不是很有用。