2013-03-19 47 views
5

我想在使用lambdas的C++ 11中编写FizzBu​​zz,但是我收到了一个奇怪的编译器错误。带lambda的FizzBu​​zz.cpp?

代码:

#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 
+6

'list range(0,100);'不*做你认为它做的事。 – 2013-03-19 20:17:52

+1

这对于''for_each'永远是效率最低的。 – 2013-03-19 20:26:19

+0

除非你让你的lambda'mutable',否则值捕获是不变的。 – 2013-03-19 20:27:10

回答

10

你应该捕获通过在拉姆达参考,而不是捕捉由值:

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

这也正好解决问题 - 生成的羊羔的调用操作符da闭合默认标记为const


注:

的另一种方式,使这个编译是使用mutable关键字,如下面的代码片段:

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

mutable关键字丢弃的效果const在生成的lambda闭包的调用操作符中。

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

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


UPDATE:

正如丹尼尔·弗雷在评论中指出,该指令:

list<int> range(0, 100); 

将创建大小为0的列表,它的元素(其元素)都用值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 
+2

单独'mutable'不会解决问题,'strings'是一个数组。 – Praetorian 2013-03-19 20:20:49

+0

@Praetorian:它似乎编译[here](http://liveworkspace.org/code/yJL1f$27)虽然... – 2013-03-19 20:21:38

+0

地球上的数组是如何可复制的?也许捕获的值是在数组之后指向隐式转换?另外,从VS2012 *错误C3478:'strings':数组不能被俘获*。但是LWS上的所有2个编译器都会编译它。 – Praetorian 2013-03-19 20:23:15

1

这种变化应修复它,所以你通过引用捕获:

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

而且丹尼尔和安迪指出你的range初始化可能不是你所期望的,因为它创建了一个zero大小的列表:

list<int> range(0, 100);