8

I am experimenting with lambda use and when testing the following it compile say 'hi'.

auto lmda = [](std::ostream& os) -> std::ostream& { os << "hi"; return os; };
std::cout << lmda;

But when adding capture, it does not compile. Example:

std::vector<int> v(5, 3);
auto lmda = [&v](std::ostream& os) -> std::ostream& { os << v.size(); return os; };
std::cout << lmda;

Build error is:

In function 'int main()':
10:18: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
In file included from /usr/include/c++/4.9/iostream:39:0,
             from 2:
/usr/include/c++/4.9/ostream:602:5: note: 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 = main()::<lambda(std::ostream&)>]'
 operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)

I don't get why it fails in the second example. Any lead?

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Mohamed B
  • 83
  • 1
  • 5

3 Answers3

6

A lambda without a capture is convertible to a function pointer which will match the following overload:

basic_ostream& operator<<(
std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&) );

As the cppreference links notes:

Calls func(*this);. These overloads are used to implement output I/O manipulators such as std::endl.

from the draft C++11 standard section 5.1.2 [expr.prim.lambda]:

The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • Note: this overload exists so that manipulators like `std::endl` and `std::boolalpha` work. They could've just been `struct`s with overloaded `<<` operators but hindsight. – Simple Oct 23 '15 at 11:02
  • @Simple good point, that was noted in the cppreference link I included but added it the answer. – Shafik Yaghmour Oct 23 '15 at 11:32
3

A lambda with no capture is convertible to a pointer-to-function.

[5.1.2/6] The closure type for a non-generic lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function with C ++ language linkage (7.5) having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.

A lambda with capture is not convertible to anything printable.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
2

You are defining a function that accepts a stream, uses it and then return the same stream.

A possible use of it follows:

#include <functional>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> v(5, 3);
    auto lmda = [&v](std::ostream& os) -> std::ostream& { os << v.size(); return os; };
    lmda(std::cout) << std::endl;
}
skypjack
  • 49,335
  • 19
  • 95
  • 187