C++ lambda函数中捕获的变量

C++ lambda函数中捕获的变量,c++,lambda,c++11,C++,Lambda,C++11,我有一个为文明V创建地图的应用程序。作为一个有趣的设计选择,我决定创建两个函数,为我完成地图的循环。通过这种方式,我可以将一个函数指针或lambda函数传递给该函数,该函数将遍历整个映射,并对每个图块执行某些操作。这背后的原因是,如果我或其他人要更改映射的存储方式(从2D数组到2D向量或其他),那么只需要更改一个函数,而不是整个代码库 现在的问题是,这里有一些代码 错误代码 case ALL_SNOW: m.loop_through_limit([] (Tile* t)

我有一个为文明V创建地图的应用程序。作为一个有趣的设计选择,我决定创建两个函数,为我完成地图的循环。通过这种方式,我可以将一个函数指针或lambda函数传递给该函数,该函数将遍历整个映射,并对每个图块执行某些操作。这背后的原因是,如果我或其他人要更改映射的存储方式(从2D数组到2D向量或其他),那么只需要更改一个函数,而不是整个代码库

现在的问题是,这里有一些代码

错误代码

    case ALL_SNOW:
        m.loop_through_limit([] (Tile* t) {
            t = new Snow(t->get_x(), t->get_y()); 
            return t;
        }, x, y, width, height);
        break;
    case PTN_ONE:
        m.loop_through_limit([&] (Tile* t) {
            int cur_x = t->get_x();
            int cur_y = t->get_y();
            t = new Plains(cur_x, cur_y);
            // if (y <= height/4 || y >= (height*3)/4) {
            //     Top quarter rows and bottom quarter rows
            //     t = new Ocean(cur_x, cur_y);
            // } else if (cur_x <= width/4) {
            //     Leftmost columns
            //     t = new Ocean(cur_x, cur_y);
            // } else if (cur_x >= (width*3)/4) {
            //     Rightmost columns
            //     t = new Desert(cur_x, cur_y);
            // } 
            return t;
        }, x, y, width, height);
        break;
现在,每种情况下的差异与注释掉的代码相差不大。这个很好用。当我注释掉if语句块时,这就是我的输出

c++ -c  -g -O3 -ffast-math -Wall -Weffc++ -std=c++0x -o tile_block.o tile_block.cpp 
tile_block.cpp: In static member function ‘static void TileBlock::write(Map&, TileBlock::Patterns, int, int, int, int)’:
tile_block.cpp:82:35: error: no matching function for call to ‘Map::loop_through_limit(TileBlock::write(Map&, TileBlock::Patterns, int, int, int, int)::<lambda(Tile*)>, int&, int&, int&, int&)’
tile_block.cpp:82:35: note: candidate is:
map.h:26:10: note: void Map::loop_through_limit(Tile* (*)(Tile*), int, int, int, int)
map.h:26:10: note:   no known conversion for argument 1 from ‘TileBlock::write(Map&, TileBlock::Patterns, int, int, int, int)::<lambda(Tile*)>’ to ‘Tile* (*)(Tile*)’
c++-c-g-O3-ffast math-Wall-Weffc++-std=c++0x-o tile\u block.o tile\u block.cpp
tile_block.cpp:在静态成员函数“static void TileBlock::write(Map&,TileBlock::Patterns,int,int,int)”中:
tile_block.cpp:82:35:错误:通过限制(TileBlock::write(Map&,TileBlock::Patterns,int,int,int)::,int&,int&,int&,int&)调用“Map::loop_”时没有匹配函数
tile_block.cpp:82:35:注:候选人为:
map.h:26:10:note:void映射::循环通过限制(Tile*(*)(Tile*),int,int,int,int)
map.h:26:10:注意:参数1没有已知的从“TileBlock::write(map&,TileBlock::Patterns,int,int,int)::”到“Tile*(*)(Tile*)”的转换
我相信当我开始使用我试图通过引用捕获的参数时,问题就来了。然后它开始变成一个“lambda”函数,而不是一个“函数指针”,也许我就是不明白

有什么建议吗

…然后它开始变成一个“lambda”函数,而不仅仅是一个 “函数指针”

这是完全正确的,标准说,不捕获任何内容的lambda可以隐式地转换为具有相同签名的函数指针

您可以通过和loop\u-through\u-limit模板创建
loop\u

template <typename F>
void loop_through(F);
template <typename F>
void loop_through_limit(F, int start_x, int start_y, int width, int height);
模板
空心环_至(F);
样板
无效循环\u到\u限制(F,int-start\u x,int-start\u y,int-width,int-height);
并在内部调用
f

…然后它开始变成一个“lambda”函数,而不仅仅是一个 “函数指针”

这是完全正确的,标准说,不捕获任何内容的lambda可以隐式地转换为具有相同签名的函数指针

您可以通过
和loop\u-through\u-limit模板创建
loop\u

template <typename F>
void loop_through(F);
template <typename F>
void loop_through_limit(F, int start_x, int start_y, int width, int height);
模板
空心环_至(F);
样板
无效循环\u到\u限制(F,int-start\u x,int-start\u y,int-width,int-height);

并在内部调用
f

C++11 lambda如果捕获变量,则不是函数指针。您需要的是调用
std::function
,特别是对于第二个函数,因为用于捕获变量的lambda

因此,改变这些:

void loop_through(void (*)(Tile* t));
void loop_through_limit(Tile* (*)(Tile* t), /*...*/);
对这些:

void loop_through(std::function<void(Tile*)>  fun);
void loop_through_limit(std::function<Tile*(Tile*)> fun, /*...*/);
void循环(std::function fun);
无效循环通过限制(标准::函数fun,/*…*/);

现在可以将lambda传递给上述函数。

C++11如果lambda捕获变量,则它们不是函数指针。您需要的是调用
std::function
,特别是对于第二个函数,因为用于捕获变量的lambda

因此,改变这些:

void loop_through(void (*)(Tile* t));
void loop_through_limit(Tile* (*)(Tile* t), /*...*/);
对这些:

void loop_through(std::function<void(Tile*)>  fun);
void loop_through_limit(std::function<Tile*(Tile*)> fun, /*...*/);
void循环(std::function fun);
无效循环通过限制(标准::函数fun,/*…*/);

现在,您可以将lambda传递给上述函数。

lambda通常作为functor(带有重载的
操作符()的对象)实现。For lambas without捕获标准保证,它们可以隐式转换为具有相同签名的函数指针(安全,因为lambda functor不包含数据)。对于捕获不安全且因此被禁止的lambda

为了实现这一点,您需要通过
更改
loop\u和
loop\u-to\u-limit
方法,以采用
std::function

void loop_-through(std::function);
void loop_至_limit(标准::函数func,int start_x,int start_y,int width,int height);
或模板函数采用任何类型的可执行函数对象

template<typename F> void loop_through_limit(F func);
template<typename F> void loop_through_limit(F func, int start_x, int start_y, int width, int height);
模板无效循环通过限制(F func);
模板无效循环通过限制(F func、int start x、int start y、int width、int height);

后一种方法的优点是开销较低(无需构造
std::function
对象),而前一种方法的优点是不将方法作为模板,因此它可以是虚拟的。

lambda通常作为functor实现(带有重载
操作符()的对象)。For lambas without捕获标准保证,它们可以隐式转换为具有相同签名的函数指针(安全,因为lambda functor不包含数据)。对于捕获不安全且因此被禁止的lambda

为了实现这一点,您需要通过
更改
loop\u和
loop\u-to\u-limit
方法,以采用
std::function

void loop_-through(std::function);
void loop_至_limit(标准::函数func,int start_x,int start_y,int width,int height);
或模板函数采用任何类型的可执行函数对象

template<typename F> void loop_through_limit(F func);
template<typename F> void loop_through_limit(F func, int start_x, int start_y, int width, int height);
模板无效循环通过限制(F func);
模板无效循环通过限制(F func、int start x、int start y、int width、int height);
后一种方法的优点是开销较低(无需构造
std::function
对象),而前一种方法的优点是不将方法作为模板,因此它可以是虚拟的