FizzBu​​zz.cpp与lambdas?

时间:2013-03-19 20:14:00

标签: c++ c++11 lambda

我尝试使用lambdas在C ++ 11中编写FizzBu​​zz,但我得到了一个奇怪的编译器错误。

代码:

#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(); }

跟踪:

$ 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

2 个答案:

答案 0 :(得分:10)

你应该通过引用捕获,而不是通过lambda中的值捕获:

for_each(range.begin(), range.end(), [&](int i) {
//                                    ^
    strings[i] = fizzy(i);
    });

这也恰好解决了这个问题 - 生成的lambda闭包的调用操作符默认标记为const


注意:

进行此编译的另一种方法是使用mutable关键字,如下面的代码段所示:

for_each(range.begin(), range.end(), [=](int i) mutable {
//                                              ^^^^^^^
    strings[i] = fizzy(i);
    });

mutable关键字具有在生成的lambda闭包的调用运算符中删除const的效果。

但是,我相信你确实想要这样:为什么修改数组中的字符串,你会忘记函数何时返回?

通过引用捕获将解决您的问题。


<强>更新

正如Daniel Frey在评论中指出的那样,这条指令:

list<int> range(0, 100);

将创建一个大小为零的列表,其元素(其元素)全部用值100初始化。可能不是您想要的。您可能希望将其更改为以下内容(std::iota仅在您使用C ++ 11时可用,否则您必须展开自己的分配循环):

#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

答案 1 :(得分:1)

此更改应修复它,因此您可以通过引用捕获:

for_each(range.begin(), range.end(), [&strings](int i) {
  strings[i] = fizzy(i);
});

同样,Daniel和Andy指出,range的初始化可能不是您所期望的,因为它创建了zero大小的列表:

list<int> range(0, 100);