【发布时间】:2016-04-30 23:40:18
【问题描述】:
我想实现一个简单的运行时检查宏,所以它的工作方式如下:
CHECK(expr) << "Some problem!";
为此我编写了一个简化的日志记录类:
class Log {
public:
Log() = default;
Log(const Log&) = delete;
~Log() {
cout << this << " dtor" << endl;
cout << stream_.str() << endl;
}
template <class T>
Log& operator<<(const T& info) {
cout << this << " <<" << endl;
stream_ << info;
return *this;
}
private:
stringstream stream_;
};
让宏为:
#define CHECK(expr) \
if (!(expr)) [] { /* See attempts below */ }()
现在让我们尝试实现 lambda。
尝试 #1
最简单的方法应该是:
[] {
Log log;
log << "A";
return log;
}
但是no luck - 复制构造函数被删除了:
error: use of deleted function 'Log::Log(const Log&)'
尝试 #2
好的,让我们显式移动局部变量:
[] {
Log log;
log << "A";
return move(log);
}
嗯,还是no luck。
尝试 #3
一个肯定行不通的绝望尝试:
[]() -> Log&& {
Log log;
log << "A";
return move(log);
}
它编译甚至runs,但是operator <<在析构函数之后被调用:
0xbfe84064 dtor
A
0xbfe84064 <<
帮我弄清楚从 lambda 返回变量我做错了什么?
【问题讨论】:
-
我真的会避免从函数返回局部变量(包括 lambda 表达式)。在你的情况下 - 只是
#define CHECK(e) if (!(e)) Log{} << "A"。由于其他原因更好#define CHECK(e) if (e) {} else Log{} << "A" -
@PiotrNycz 这对我来说不是一个好的变体,因为我想打印堆栈跟踪以及用户提供的消息 - 这就是为什么我在 lambda 中使用
Log来做一些事情。跨度> -
完全没有问题。您可以创建打印堆栈跟踪的对象 - 例如
Log{} << stackTracePrinter。或者你可以在一些 Log 专业化构造函数中做你能想象的一切......
标签: c++ c++11 lambda move-semantics