Ошибка с лямбда в функции-члена шаблона - PullRequest
0 голосов
/ 27 февраля 2020

У меня есть следующий код C ++

#include <iostream>

template<typename Func>
class Foo
{
private:
    Func func;

public:
    Foo(Func func) : func(func) {}

    template<typename T>
    Func wrap()
    {
        Func clbk = func;
        auto wrapperCB = [clbk](T t) {
            auto job = [clbk, t](){
                clbk(t);
            };
            job();
        };

        return wrapperCB;
    }

    template<typename T>
    void call(T t)
    {
        func(t);
    }
};

int main()
{
  int m = 2;
  auto f = [](int & p) {std::cout << "test success " << p << "\n";};
  auto obj = std::make_shared<Foo<std::function<void(int &)>>>(f);
  auto wrapper = obj->template wrap<int &>();
  wrapper(m);
  return 0;
}

Это дает ошибку компиляции

tsavs-mbp:p utsagarw$ clear; g++ -std=c++11 a.cpp -o z; ./z
a.cpp:18:17: error: no matching function for call to object of type 'const std::__1::function<void (int &)>'
                clbk(t);
                ^~~~
a.cpp:38:32: note: in instantiation of function template specialization 'Foo<std::__1::function<void (int &)> >::wrap<int &>' requested here
  auto wrapper = obj->template wrap<int &>();
                               ^
/Applications/Xcode_10.1/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1677:9: note: candidate function not viable: 1st argument ('const int') would lose const qualifier
    _Rp operator()(_ArgTypes...) const;
        ^
1 error generated.

Я не понимаю эту ошибку. Откуда взялась эта константа?

Она успешно строится, если в wrap я не создаю функтор job и не вызываю clbk напрямую. Что это job делает с type T?

template<typename T>
Func wrap()
{
    Func clbk = func;
    auto wrapperCB = [clbk](T t) {
        clbk(t);
    };

    return wrapperCB;
}

1 Ответ

2 голосов
/ 27 февраля 2020

Если вы хотите изменить любую захваченную переменную внутри лямбды, вы должны указать ее как mutable.

t Переменная захватывается копией, поэтому вы можете только читать ее:

         auto job = [clbk, t]()  // <-- t passed by copy
         {
             clbk(t);            // clbk takes t by reference -> int&
         };

ваш обратный вызов, clbk имеет подпись int&, поэтому он может изменить t. Что не разрешено.

Решение:

         auto job = [clbk, t]() mutable // keyword 'mutable' added
         {
             clbk(t);  // clbk can change t
         };

или сделать function, принимая const int& в качестве параметра - тогда t может быть только прочитано.

Демо

...