I'm trying to write FizzBuzz in C++11 using lambdas, but I'm getting a weird compiler error.
Code:
#include <iostream>
#include <string>
#include <sstream>
#include <list>
#include <algorithm>
using namespace std;
string fizzy(int n) {
int a = n % 3, b = n % 5;
if (a == 0 && b == 0) {
return "FizzBuzz";
}
else if (a == 0) {
return "Fizz";
}
else if (b == 0) {
return "Buzz";
}
else {
stringstream out;
out << n;
return out.str();
}
}
void fizzbuzz() {
string strings[100];
list<int> range(0, 100);
for_each(range.begin(), range.end(), [=](int i) {
strings[i] = fizzy(i);
});
for_each(range.begin(), range.end(), [=](int i) {
cout << strings[i] << endl;
});
}
int main() { fizzbuzz(); }
Trace:
$ make
g++ -std=c++0x -o fizzy fizzy.cpp
fizzy.cpp: In lambda function:
fizzy.cpp:32:27: error: passing 'const std::string' as 'this' argument of 'std::basic_string<_CharT,
_Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(std::basic_string<_CharT, _
Traits, _Alloc>&&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<ch
ar>, std::basic_string<_CharT, _Traits, _Alloc> = std::basic_string<char>]' discards qualifiers
make: *** [fizzy] Error 1
You should capture by reference instead of capturing by value in your lambda:
for_each(range.begin(), range.end(), [&](int i) {
// ^
strings[i] = fizzy(i);
});
That also happens to solve the problem - the call operator of a generated lambda closure is marked as const
by default.
NOTE:
Another way to make this compile is to use the mutable
keyword, as in the snippet below:
for_each(range.begin(), range.end(), [=](int i) mutable {
// ^^^^^^^
strings[i] = fizzy(i);
});
The mutable
keyword has the effect of dropping the const
in the call operator of the generated lambda closure.
However, I do believe you really do not want this: why modifying strings in an array that you will forget about when the function returns?
Capturing by reference will solve your problem.
UPDATE:
As pointed out by Daniel Frey in the comments, this instruction:
list<int> range(0, 100);
Will create a list of size zero, whose elements (whose zero elements) are all initialized with the value 100. Probably not what you want. You may want to change it into something like the following (std::iota
is only available if you are working with C++11, otherwise you'll have to unroll your own loop of assignments):
#include <algorithm>
list<int> range(100); // Creates a list of 100 elements
iota(begin(range), end(range), 0); // Assigns value 0..99 to those elements
This change should fix it, so you capture by reference:
for_each(range.begin(), range.end(), [&strings](int i) {
strings[i] = fizzy(i);
});
Also as Daniel and Andy point out your initialization of range
is probably not what you expect since it creates a zero
sized list:
list<int> range(0, 100);
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