我一直在尝试重做我的测井类(class)。但是,我面临一个问题。
我想向用户展示此界面:

mylog() << "hello";

这个想法是mylogLogger的实例,它为已定义的日志类型定义了一些有用的特性。它的operator()函数将返回LogStream类型的实例。但是,我想在最后自动输出换行符,因此我有想法在LogStream的析构函数中进行操作。

我当前的实现看起来像这样(LogStreamLogger被大大简化了):
#include <iostream>

struct LogStream
{
    ~LogStream() { std::cout << '\n'; }

    template<class T>
    LogStream& operator<<(const T& t)
    {
        std::cout << t;
        return *this;
    }
};

struct Logger
{
    LogStream operator()()
    {
        return LogStream{} << "message: ";
    }
};

int main()
{
    Logger log;
    log() << "hello!";
}

有趣的是,我发现这段代码表明我以前的实现依赖于RVO。编译器始终在执行复制删除操作,因此析构函数的行为确实符合我想要的方式。但是,使用这段代码,换行符将被打印两次,因为在operator()中进行复制时,将调用复制构造函数。
当我不返回临时实例时,问题消失了,而是将其放在operator()的主体中:
LogStream stream;
stream << "message: ";
return stream;

现在,RVO使它按我想要的方式工作。
后来我在= delete上使用了复制构造函数,因为无论如何它都更有意义,这实际上导致代码无法编译。

在不使用hacky解决方案依赖RVO的情况下,我可以提供哪些选项以提供所需的界面?

最佳答案

将一个构造函数添加到LogStream中,并采用char const *

LogStream(char const* c) { std::cout << c; }

然后,不要在LogStream中创建临时的operator(),而使用list-initialization初始化返回值本身。
LogStream operator()()
{
    return {"message: "};
}

因此避免了临时操作以及额外的新行。

Live demo(请注意,即使使用-fno-elide-constructors禁用复制省略也不会导致多余的换行符)。

08-27 22:03