I'm trying to use C++11 features to make custom stream manipulators easier to create. I can use lambda functions as manipulators, but not std::function<ostream&(ostream&)>
.
Here's the code, boiled down:
#include <iostream>
#include <functional>
using namespace std;
auto lambdaManip = [] (ostream& stream) -> ostream& {
stream << "Hello world" << endl;
};
function<ostream& (ostream&)> functionManip = [] (ostream& stream) -> ostream& {
stream << "Hello world" << endl;
};
int main (int argc, char** argv) {
cout << lambdaManip; // OK
cout << functionManip; // Compiler error
}
The second cout
statement fails with the following:
g++-4 src/Solve.cpp -c -g -std=c++0x -o src/Solve.o -I/home/ekrohne/minisat
src/Solve.cpp: In function 'int main(int, char**)':
src/Solve.cpp:24:11: error: cannot bind 'std::ostream' lvalue to 'std::basic_ostream<char>&&'
/usr/lib/gcc/i686-pc-cygwin/4.5.3/include/c++/ostream:579:5: error: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char, _Traits = std::char_traits<char>, _Tp = std::function<std::basic_ostream<char>&(std::basic_ostream<char>&)>]'
Why does this fail? I'm using cygwin gcc 4.5.3.
While I'm asking, I'm not nuts about using std::function
everywhere, due to the efficiency problems. But I do wish to write functions that return lambda functions, and have no idea how to do so without std::function
. For example, something like the following would be great
auto getAdditionFunctor();
auto getAdditionFunctor() {
return [] (int x, int y) { return x + y };
};
...but obviously does not work. Is there an alternate syntax that does work? I can't imagine what it could be, so I may be stuck with std::function
.
If I had a solution to the second question, then the first question would be moot.
Thank you.
Defining operator<<(ostream&, std::function<ostream&(ostream&)>
helped. I had misread a web page, and was under the impression that ostream
was smart enough to treat an arbitrary object that had an operator()
as a manipulator. I was wrong about this. Furthermore, the simple lambda
I built was probably just getting compiled into a plain old function, just as I was told. Indeed, if I use variable capture to ensure that the lambda
is not a simple function, then the compiler fails. Also, objects with operator()
defined are not (by default) treated as manipulators:
class Manipulator {
ostream& operator()(ostream& stream) const {
return stream << "Hello world" << endl;
};
} classManip;
function<ostream& (ostream&)> functionManip = [] (ostream& stream) -> ostream& {
return stream << "Hello world" << endl;
};
int main (int argc, char** argv) {
const string str = "Hello world";
auto lambdaManip = [&] (ostream& stream) -> ostream& {
return stream << str << endl;
};
cout << classManip; // Compiler error
cout << lambdaManip; // Compiler error
cout << functionManip; // Compiler error
}
Further update: it turns out a slightly more robust solution than the ones below can be accomplished with:
// Tell ostreams to interpret std::function as a
// manipulator, wherever it sees one.
inline ostream& operator<<(
ostream& stream,
const function<ostream& (ostream&)>& manipulator) {
return manipulator( stream );
}
This code has an extra const
. I discovered this trying to actually implement the solution in my project.
A parameterized manipulator is implemented in two parts: The manipulator. It takes an extra parameter. In the previous code example, it takes an extra int parameter. You cannot place this manipulator function in a sequence of input or output operations, since there is no shift operator defined for it.
setfill (near the bottom of the iomanip. h header file) is an example of a parameterized manipulator. You can create your own parameterized manipulators and your own simple manipulators.
Stream Manipulators are functions specifically designed to be used in conjunction with the insertion (<<) and extraction (>>) operators on stream objects, for example − std::cout << std::setw(10);
If you look at operator<<
for ostream
, there's no overload for taking a std::function
- and that's basically what you're trying to do here with cout << functionManip
. To fix this, either define the overload yourself:
ostream& operator<<(ostream& os, std::function<ostream& (ostream&)>& s)
{
return s(os);
}
Or pass the stream
as an argument to the function:
functionManip(std::cout);
As for why the lambda
is working, given that the return type of a lambda
is undefined, and there is an overload for using a function pointer:
ostream& operator<< (ostream& ( *pf )(ostream&));
The lambda is probably wrapping everything utilizing a a struct and defining operator()
which in this case will work exactly like a function pointer. This to me is the most likely explanation, hopefully someone can correct me if I'm wrong.
This isn't the cause of the error, but since you've defined both lambdaManip
and functionManip
as having the return type ostream&
I believe you've forgotten to add return stream;
to both.
The call cout << functionManip
fails because there is no operator<<(ostream&, std::function<ostream&(ostream&)>
defined. Add one and the call will succeed.
ostream& operator<<(ostream& stream, function<ostream& (ostream&)>& func) {
return func( stream );
}
Alternatively, you can call functionManip
as
functionManip( cout );
This will work without adding the operator<<
definition.
As for your question about returning a lambda, since the lambda returned by getAdditionFunctor
is a capture-less lambda, it can be implicitly converted to a function pointer.
typedef int(*addition_ptr)(int,int);
addition_ptr getAdditionFunctor()
{
return [] (int x, int y) -> int { return x + y; };
}
auto adder = getAdditionFunctor();
adder(10,20); // Outputs 30
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With