Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::mem_fn with ref_qualified member functions

Tags:

Is there any way by which we can make use of ref qualified member functions with std::mem_fn ?

The below code fails to compile:

class DeadPool {
public:
  void jump() & {
    std::cout << "Did not jump\n";
  }

  void jump() && {
    std::cout << "Jumped from helicopter\n";
  }
};

int main() {
  DeadPool dp1;
  //auto cobj = std::mem_fn(&DeadPool::jump); // Won't compile
  //cobj(dp1);
  //cobj(DeadPool());
  using Func = void (DeadPool::*) () &; // lvalue ref qualifier explicitly provided
  Func fp = &DeadPool::jump; // This works, as expected
  (std::move(dp1).*fp)();
  return 0;
}

Error message:

mem_fn_ex.cc:18:15: error: no matching function for call to 'mem_fn'
auto cobj = std::mem_fn(&DeadPool::jump); // Won't compile ^~~~~~~~~~~ /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/functional:1233:1: note: candidate template ignored: couldn't infer template argument '_Rp' mem_fn(_Rp _Tp::* __pm) ^ mem_fn_ex.cc:23:18: error: pointer-to-member function type 'Func' (aka 'void (DeadPool::*)() &') can only be called on an lvalue (std::move(dp1).*fp)(); ~~~~~~~~~~~~~~^

Compiler: On both Clang(3.4) and g++ (5.3)

I thought I could make use of the fact that, in std::_Mem_fn class implementation an rvalue object is invoked like below:

return (std::move(__object).*__pmf)(std::forward<_Args>(__args)...);

This could have very well invoked the member function specific for rvalue this, but since the signatures are different at compile time, it cannot do that.

like image 658
Arunmu Avatar asked Jul 23 '16 15:07

Arunmu


1 Answers

The problem is that you're passing an overloaded function into a function template - mem_fn() can't deduce which jump() you want. You would need to pass a specific one with a cast:

auto cobj = std::mem_fn(static_cast<void (DeadPool::*)() &>(&DeadPool::jump));
cobj(dp1);        // ok
cobj(DeadPool()); // error

However, that's a really unsatisfying solution due to both the verbosity (that's a LOT to type) and the limitations (you have &- and &&-qualified overloads for a reason, but you can only use one?). Better to use a generic lambda here:

auto jump = [](auto&& pool){ std::forward<decltype(pool)>(pool).jump(); };
jump(dp1);         // ok: Did not jump
jump(DeadPool());  // ok: Jumped from helicopter
like image 134
Barry Avatar answered Sep 28 '22 03:09

Barry