3

This is my stripped-down program, where I'm trying to use function variables to modify class functionality at run time. So - I declare a member variable m_func using the std::function template and a function myFunc with compatible signature:

#include <functional>
#include <iostream>

struct T
{
  T():m_func([](int){return true;}) {}
  void assign() {m_func = &T::myFunc;}    // <======== Problem is here
  void call(int M) const {std::cout << m_func(M) << std::endl;}
private:
  bool myFunc(int N) {return (N >= 4);}
  using func = std::function<bool(int)>;
  func m_func;
};

int main()
{
  T t;
  t.assign();
  t.call(6);
}

However, the compiler (g++ 4.8.4 with -std=c++11 option) gives me an error with long output, saying that template argument deduction/substitution failed and a lot more...

Why can't I assign the myFunc function to the m_func variable?

HEKTO
  • 3,876
  • 2
  • 24
  • 45

4 Answers4

5

A non-static member function pointer cannot be assigned to std::function directly. The general solution for this problem is to bundle the this pointer into a lambda like this :

void assign() { 
    m_func = [this](int N) { 
        return this->myFunc(N); 
    };
}

In your case, it seems simpler to just make myFunc static.

struct T
{
    T() :m_func([](int) {return true; }) {}
    void assign() { m_func = &T::myFunc; }
    void call(int M) const { std::cout << m_func(M) << std::endl; }
private:
    static bool myFunc(int N) { return (N >= 4); }
//  ^^^^^^ static methods can be assigned to std::function directly
    using func = std::function<bool(int)>;
    func m_func;
};
François Andrieux
  • 28,148
  • 6
  • 56
  • 87
  • Thanks! I can't make the `myFunc` static, cause in reality it needs to access a bunch of member variables – HEKTO Feb 21 '17 at 23:27
4

If you want the member function to be called on the current object, then you want:

m_func = std::bind(&T::myFunc, this, std::placeholders::_1);
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
2
void assign() {m_func = &T::myFunc;}

Member function pointers have an implicit this pointer that needs to be passed as the first argument in their signature. Either use std::bind to bind that first,

void assign() {
    m_func = std::bind(&T::myFunc, this, std::placeholders::_1);
}

or use a lambda-expression (capturing this).

void assign() {
    m_func = [this](int arg){ return this->myFunc(arg); };
}
BadAtLaTeX
  • 614
  • 1
  • 9
  • 22
WhiZTiM
  • 21,207
  • 4
  • 43
  • 68
1

As mentioned by @Kerrek SB above, you could use std::bind.

However, it's better to use a lambda since it can have less overhead :

m_func = [this] (int N) {return myFunc(N);};
Telokis
  • 3,399
  • 14
  • 36