3

Heoi, I've seen a C++ talk where someone made a lambda fizzbuzz implementation.

This is not it! Not even close to it! My question is, why can't I use the ostream&

auto fizz = [](int& x, std::ostream& os) { x % 3 == 0 ? os << "fizz" : 0; };
auto buzz = [](int& x, std::ostream& os) { x % 5 == 0 ? os << "buzz" : 0; };


    for (int i = 0; i != 100; ++i)
    {
        fizz(i, std::cout);
        buzz(i, std::cout);
    }

And my Error message is :

        E1776   function "std::basic_ostream<_Elem, _Traits>::basic_ostream(const std::basic_ostream<_Elem, _Traits>::_Myt &) [with _Elem=char, _Traits=std::char_traits<char>]" (declared at line 83 of "c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.12.25827\include\ostream") cannot be referenced -- it is a deleted function    56  
FistyTries
  • 109
  • 11
  • 2
    Don't know what MSVC is trying to do here, but Clang gives `error: incompatible operand types ('basic_ostream >' and 'int')`. Bottom line: stop abusing the conditional operator, use an `if` instead. – Quentin Jan 31 '18 at 18:04
  • oops, couldn't post the code comment, auto buzz = [](std::ostream& os) { os << "buzz"; }; But why not inside the inline-if??? – FistyTries Jan 31 '18 at 18:06
  • 2
    `? X : Y` returns either `X` or `Y`. Because you cannot have types decided at runtime `X` and `Y` must have at least a common type. `std::ostream` and `int` do not have a common type, so it fails to compile. Since you don't actually want the `0` or the return value of `?:` you should simply write `if (x % 3 == 0) os << "fizz";`. – nwp Jan 31 '18 at 18:10

1 Answers1

4

Your problem is quite clear. Since std::ostream and int are not of the same type, providing types that are not the same to the ternary operator creates an error. To solve this, you probably want to avoid an else clause altogether, so your functions would look like this:

auto fizz = [](int& x, std::ostream& os) { if (x % 3 == 0) os << "fizz"; };
auto buzz = [](int& x, std::ostream& os) { if (x % 5 == 0) os << "buzz"; };

Arnav Borborah
  • 11,357
  • 8
  • 43
  • 88
  • Might help to further clarify to OP that `os << "fizz"` actually returns `os`, which is type `ostream`. Since their question doesn't show chaining they might not be aware of it or understand how it works. – Nir Friedman Jan 31 '18 at 18:20
  • @NirFriedman I don't understand what you are saying about chaining (more specifically how it relates to this example). – Arnav Borborah Jan 31 '18 at 18:24
  • I really need to find that talk again, there was a beautiful `inline-if` – FistyTries Jan 31 '18 at 18:25
  • `<<'`operator is a function that returns an `ostream` object hence the chaining of `<< x << endl` calls on each returned obj, but had no clue that it affected the functions return like that. Thx a lot! – FistyTries Jan 31 '18 at 18:26
  • Ok, so you do understand it, so I presume you do not need any clarification @FistyTries? – Arnav Borborah Jan 31 '18 at 18:27
  • Also, technically this answer isn't quite right: it makes it sound like the problem is with the lambda ("returning types") but the problem actually occurs earlier, in the ternary operator. – Nir Friedman Jan 31 '18 at 18:29
  • @ArnavBorborah nono, edited previous message. Got the point I think! – FistyTries Jan 31 '18 at 18:29
  • @NirFriedman Nope... the point is gone! Could you expand a bit? – FistyTries Jan 31 '18 at 18:31
  • 1
    @FistyTries `os << "fizz"` is an expression, and that expression actually returns a reference to `os`. That's why `os << "fizz" << "buzz"` works; it evaluates from left to right, so after evaluating `os << "fizz"`, you have a reference to os, so it then does `os << "buzz"`. So your ternary expression actually returns `os` in one branch, but an int (0) in the other. A ternary expression has compile time fixed return type, so the expressions in both branches must be of same (or compatible) type. – Nir Friedman Jan 31 '18 at 18:41