0

A lambda expression has been defined and assigned/binded to a function object. Now I'd like to assign a new function to that function object. But this assignment casuses compile error in some cases.

I understand that the error comes from the auto keyword automatically adding const to the function object. Is there anyway to use auto together with other key words to remove the const binding? I don't really believe mutable can serve the purpose as in my code.

This post explains why without a solution. This post proposes a solution using a struct, but I wonder if there is a more elegant way to do it.

#include <functional>
#include <memory>
#include <queue>
#include <random>
#include <utility>

using namespace std;

void f1();

int main() {
  srand(0);
  f1(); 
  return 0;
}

void f1() {
  using my_pair = pair<int,int>;
  int ref = 2;
  function<bool(const my_pair &,const my_pair &)> comp_1 = [&ref](const my_pair &LHS, const my_pair &RHS) {return LHS.first-ref > RHS.first-ref;};
  comp_1 = [&ref](const my_pair &LHS, const my_pair &RHS) {return LHS.first < RHS.first;};
  // So far so good.
  auto comp_2 = [&ref](const my_pair &LHS, const my_pair &RHS) mutable {return LHS.first-ref > RHS.first-ref;};
    // Compile error below!
  comp_2 = [&ref](const my_pair &LHS, const my_pair &RHS) mutable {return LHS.first < RHS.first;};
    // Compile error above

    // Applications of the function object
  priority_queue<my_pair, vector<my_pair>, decltype(comp_2)> myHeap(comp_2);
  for (int i=0; i<10; i++) myHeap.emplace(rand()%10,rand()%20);
  while (!myHeap.empty()) {
    printf("<%d,%d>\n",myHeap.top().first,myHeap.top().second);
    myHeap.pop();
  }

}
user3813057
  • 891
  • 3
  • 13
  • 31
  • 3
    The exact error message would be a useful thing to have. – Borgleader Jan 22 '18 at 14:36
  • 8
    *"I understand that the error comes from the auto keyword automatically adding const"* what? The problem here is that `auto` is deduced as the lambda type, not `std::function`, and each lambda has its own type, so you cannot assign a new lambda to the previous one. – Holt Jan 22 '18 at 14:38
  • `comp_2` type is the type of the lambda given to initialize it... The 2 lambdas have 2 distinct types. – Jarod42 Jan 22 '18 at 14:38
  • You can use `using MyFunc_t = function;` or `typedef` to get a shorter name and use it instead of `auto comp_2 = ...` - `MyFunc_t comp_2 = ...`. – Mihayl Jan 22 '18 at 14:41
  • You *could* pass the different implementations [through a lambda to unify the types](http://coliru.stacked-crooked.com/a/73c480dc3cc561c8). I'd not recommend doing so however--the error quality reduces significantly given you're calling the variadic lambda result of passing a lambda into a generic lambda. – jaggedSpire Jan 22 '18 at 21:31

1 Answers1

3

Each lambda expression is a literal of a anonymous type; two different lambdas, even of the same prototype and the same capture list, are objects of two distinct types. Moreover, this type's assignment operator is deleted, so you could not even possibly assign it to itself:

$ cat omg.cpp
int main() {
    auto f = []{};
    f = f;
}
$ g++ omg.cpp
omg.cpp: In function ‘int main()’:
omg.cpp:3:4: error: use of deleted function ‘main()::<lambda()>& main()::<lambda()>::operator=(const main()::<lambda()>&)’
  f = f;
    ^
omg.cpp:2:12: note: a lambda closure type has a deleted copy assignment operator
bipll
  • 11,747
  • 1
  • 18
  • 32