c++ - 如何为 ostream 创建 lambda?

标签 c++ lambda operator-overloading outputstream ostream

我以为是operator<<的电话将生成一个双参数函数调用。那么,为什么这不能编译呢?

#include <iostream> // ostream
#include <iomanip> // setw, setfill
using std::ostream; using std::setw; using std::setfill;
struct Clock {
    int h_, m_, s_;
    Clock(int hours, int minutes, int seconds)
    : h_{hours}, m_{minutes}, s_{seconds} {}
    void setClock(int hours, int minutes, int seconds) {
        h_ = hours; m_ = minutes; s_ = seconds;
    }
    friend ostream& operator<<(ostream&os, const Clock& c) {
        auto w2 = [](ostream&os, int f) -> ostream& {
            return os << setw(2) << setfill( '0' ) << f; };
        return os << w2(c.h_) <<':'<<w2(c.m_)<<':'<<w2(c.s_); // ERROR
    }
};

错误是(gcc-6)

$ g++-6 -std=gnu++1y ...
file.cpp: In function ‘std::ostream& operator<<(std::ostream&, const Clock&)’:
file.cpp:745:33: error: no match for call to ‘(operator<<(std::ostream&, const Clock&)::<lambda(std::ostream&, int)>) (const int&)’
         return os << w2(c.h_) <<':'<<w2(c.m_)<<':'<<w2(c.s_);
                             ^

我也试过调用os << w2(os,c.h_)但 gcc 和我一致认为这是无稽之谈。我还尽可能地尝试了 lambda:

auto w2 = [](auto&os, auto f) {
    return os << setw(2) << setfill( '0' ) << f; };

也没有运气。

有什么提示吗?

最佳答案

I thought the call of the operator<< would generate a two-parameter function call.

不,调用重载 operator<<与调用二元函数基本相同:

a << b;
// is equivalent to
operator<<(a, b);
// or to
a.operator<<(b);

您要做的是调用 operator<<使用返回 ostream& 的 lambda作为右边的参数,但你没有传递 ostream& lambda 本身的参数。


os << w2(os,c.h_)在语法上是有效的,但不会编译,因为没有 operator<<(ostream&, ostream&)定义。

您可以做的是简单地调用 lambda 而无需流式传输它:

friend ostream& operator<<(ostream&os, const Clock& c) {
    auto w2 = [](ostream&os, int f) -> ostream& {
        return os << setw(2) << setfill( '0' ) << f; };

    w2(os, c.h_); 
    os <<':'; 
    w2(os, c.m_); 
    os << ':'; 
    return w2(os, c.s_);
}

wandbox example


如果你想实现你想要的语法,你需要做更多的工作。这是一个可能的解决方案:

template <typename TF>
struct streamable : TF
{
    streamable(TF&& f) : TF{std::move(f)} { } 
};

template <typename TF>
auto& operator<<(ostream& os, const streamable<TF>& s)
{
    s(os); return os;
}

template <typename TF>
auto make_streamable_impl(TF f)
{
    return streamable<TF>(std::move(f));
}

template <typename TF>
auto make_streamable(TF f)
{
    return [&](auto&& x) mutable
    { 
        return make_streamable_impl([&](ostream& os) -> auto&
        { 
            f(os, x); 
            return os; 
        });
    };
}

用法:

friend ostream& operator<<(ostream&os, const Clock& c) {
    auto w2 = make_streamable([](ostream&os, int f) -> ostream& {
        return os << setw(2) << setfill( '0' ) << f; });
    return os << w2(c.h_) <<':'<<w2(c.m_)<<':'<<w2(c.s_);
}

wandbox example

请注意,真正的实现可能应该是 perfectly-capture the arguments进入 lambda。

关于c++ - 如何为 ostream 创建 lambda?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42456399/

相关文章:

c++ - UE4 - 在我从编辑器添加新的 C++ 文件后,Visual Studio 无法打开任何源文件 - UBT_COMPILED_PLATFORM 错误

c# - lambda 表达式中的枚举的编译方式不同;重载分辨率改进的结果?

c# lambda表达式+思考题

c++ - 为什么我不能将此运算符重载放在与结构相同的 namespace 中?

c++ - void()、逗号运算符 (operator,) 和不可能的 (?) 重载

java - jstring/c++ 的 Ljava/lang/String 错误

c++ - 无法在我自己的 dll 中使用 GetProcAddress 调用函数

c++ - 在 glm 和 OpenGL 中合成变换

PHP:寻找类似 Java Stream API 的东西

c++运算符在模板类中重载