5

我正在尝试使用 lambda 在 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
4

2 回答 2

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关键字的作用是在const生成的 lambda 闭包的调用运算符中删除。

但是,我相信您确实希望这样:为什么要修改数组中的字符串,而当函数返回时您会忘记呢?

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


更新:

正如 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
于 2013-03-19T20:17:21.543 回答
1

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

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

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

list<int> range(0, 100);
于 2013-03-19T20:18:49.840 回答