I have the following code that compiles and works correctly due to such a concept as Input/output manipulators:
#include <iostream>
#include <ostream>
struct st{
auto mke(){
return [](std::ostream& os) -> decltype(auto) {return os<<42;};
}
};
int main(){
std::cout<<st{}.mke();
}
But actually, in my project, I need to capture this
by reference and output some fields of the structure. Something like this:
#include <iostream>
#include <ostream>
struct st{
int a=42;
auto mke(){
return [this](std::ostream& os) -> decltype(auto) {return os<<a;};
}
};
int main(){
std::cout<<st{}.mke();
}
But it doesn't compile:
error: no match for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'st::mke()::<lambda(std::ostream&)>')
12 | std::cout<<st{}.mke();
Q: I need a detailed explanation of the reasons preventing the compilation of the second example. What really happened?
Your first example works because the standard operator<<
accepts a function pointer, and your non-capturing lambda is convertible to such a type.
Your second example fails because a capturing lambda is not convertible to a function pointer.
The typical way to solve this is to not use a lambda at all. Return a struct/class object instead, and overload operator<<
to handle that type, eg:
#include <iostream>
#include <ostream>
struct st {
int a = 42;
struct manipulator {
st& m_st;
};
manipulator mke() {
return {*this};
}
};
std::ostream& operator<<(std::ostream& os, const st::manipulator &io) {
return os << io.m_st.a;
}
int main(){
std::cout << st{}.mke();
}