Search code examples
templatesc++11decltype

decltype of member function pointer as template argument in c++11


I am trying to write a wrapper function which links to a function pointer at compile time, thus I wrote the following code which works perfectly fine in C++11:

#include <iostream>

template<typename Fn, Fn func, typename... Args>
typename std::result_of<Fn(Args...)>::type callfunc(Args&&... args){
  //do something else here
  return (*func)(args...);
}

double add(double a, double b){
  return a+b;
}

int main(){
  std::cout << callfunc<decltype(&add), &add>(2.0, 3.0) << "\n";
}

However if I try to do the same thing with a member function like this

#include <iostream>

template<typename Fn, Fn func, typename... Args>
typename std::result_of<Fn(Args...)>::type callfunc(Args&&... args){
  //do something else here
  return (*func)(args...);
}
class testclass {
public:
  double testadd(double a, double b);
  void run();
};

double testclass::testadd(double a, double b){
  return a+b;
}

void testclass::run(){
  std::cout << 
  callfunc<decltype(&testclass::testadd), &testclass::testadd>(2.0, 3.0) 
  // ^^^^^ this won't compile! ^^^^
  << "\n"; 
}

int main(){
  testclass obj;
  obj.run()
}

I get the following compiler error:

error: indirection requires pointer operand ('double (testclass::*)(double,double)' invalid) return (*func)(args...);

What am I doing wrong?


Solution

  • To invoke a non-static member function you need a valid instance pointer. Here is a modified version of your code that works:

    #include <iostream>
    
    template<typename Fn, Fn func, typename Class, typename... Args>
    typename std::result_of<Fn(Args...)>::type callfunc(Class* instance, Args&&... args){
        return (instance->*func)(args...);
    }
    class testclass {
    public:
        double testadd(double a, double b);
        void run();
    };
    
    double testclass::testadd(double a, double b){
        return a + b;
    }
    
    void testclass::run(){
        std::cout <<
            callfunc<decltype(&testclass::testadd), &testclass::testadd>(this, 2.0, 3.0)
            << "\n";
    }
    
    int main(){
        testclass obj;
        obj.run();
    }