Skip to content

Instantly share code, notes, and snippets.

@utilForever
Created February 3, 2017 01:04
Show Gist options
  • Save utilForever/ca67c54c2d68b3b81e01b3a25e88d787 to your computer and use it in GitHub Desktop.
Save utilForever/ca67c54c2d68b3b81e01b3a25e88d787 to your computer and use it in GitHub Desktop.
Call member function pointed by instantiated object (using variadic template and std::bind)
#include <iostream>
#include <functional>
class AAA
{
public:
bool A(int a, int b, int c)
{
return a + b + c > 10;
}
};
template <typename Obj, typename Func, typename... Args>
decltype(auto) CallFunc(Obj* obj, Func (Obj::*func)(Args...), Args&&... args)
{
return (obj->*func)(std::forward<Args>(args)...);
}
int main()
{
AAA* aaa = new AAA();
if (CallFunc(aaa, &AAA::A, 2, 4, 8))
{
std::cout << "Hello World\n";
}
auto fn = std::bind(&AAA::A, aaa, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
if (fn(3, 4, 5))
{
std::cout << "Hello World\n";
}
}
@luncliff
Copy link

luncliff commented Feb 3, 2017

For the first, approach at line 14 for explicit member function pointer was really inspiring code for me!

Invoke 1

// Invoke 1
template<typename Fn, typename... Args>
  auto Invoke(Fn&& fn, Args&&... args)
    -> typename std::result_of<Fn(Args...)>::type
{
    return fn(std::forward<Args>(args)...);
}

I felt that CallFunc is quite similar to std::async with its signature. And if I'm right, it uses std::bind internally.(Can't sure. Might be different upon vendors...)
I used Fn&& for funtion type deduction. Since function name is address of its code, It won't make any difference with receiving function pointer.

Invoke 2

// Invoke 2
template<typename Fn, typename Owner, typename... Args>
  auto Invoke(Fn&& fn, Owner* owner, Args&&... args)
    -> typename std::result_of<Fn(Owner*, Args&&...)>::type
{
    return (owner->*fn)(std::forward<Args>(args)...);
}

To pretend this pointer, I overloaded Invoke with second parameter as a pointer. It's simply named Owner since it owns member variables.
-> typename std::result_of<Fn(Owner*, Args&&...)>::type is explicitly noted for reader.

Use-case

#include <iostream>

struct A
{
    void member(int)
    {
        std::cout << "member" << std::endl;
        return;
    }
};

int multiply(int a, int b){
    std::cout << "normal" << std::endl;
    return a * b;
}

int main(int argc, char *argv[])
{
    A a{};

    // With the pointer to owner, deduce [Invoke 2]  
    Invoke(&A::member, &a, 2);
    
    // Without owner, deduce [Invoke 1]
    int mul = Invoke(multiply, 2, 4);  
    return 0;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment