8
votes

I'm trying to use a class function (interrupt service routine),

void (ClassName::*fp)(void)=ClassName::FunctionName;

and attaching it to an Arduino interrupt pin using the function with the following type inputs but that doesn't work.

void attachInterrupt(int, void (*)(void),int);

How can I make this happen? The interrupt service routine (ISR) needs to access privat object data, so I can't make a function outside of the class.

My compiler error:

ClassName.cpp : : In constructor 'ClassName::ClassName()':
ClassName.cpp : *)()'
ClassName.cpp : *)()' to 'void (*)()' for argument '2' to 'void attachInterrupt(uint8_t, void (*)(), int)'

Note: I am looking for a solution inside the class and will accept the answer that shows me a solution or shows me it's not possible.

3
Are you getting an error. What error is it?0x499602D2
I'm using the Visual Studio 2012 compiler. I'll put the compiler error into my question.Flying Swissman
sorry, wrong compiler error at first, now its rightFlying Swissman

3 Answers

7
votes

If the function is not static, you cannot pass it in input to a function that accepts a non-member function pointer.

Consider that a non-static member function has an implicit pointer to ClassName as its first parameter, which points to the object on which the member function is being invoked.

struct X
{
    static void foo() { } // Does not have an implicit "this" pointer argument
    void bar() { } // Has an implicit "this" pointer argument
};

int main()
{
    void (*f)() = &X::foo; // OK: foo is static
    void (*g)() = &X::bar; // ERROR! bar is non-static
}

Here, not even std::bind() will work, because the result is not convertible to a function pointer. Lambdas are convertible to function pointers, but only if they are non-capturing (and a lambda here would need to capture the object to invoke the member function on).

Therefore, the only (ugly) workaround is to have a global adapter function which invokes the member function on an object which is available through a global pointer variable. The global pointer variable is set prior to calling the function:

struct X
{
    void bar() { }
};

void function_taking_a_function_pointer(void (*f)())
{
    // Do something...
    f();
}

X* pX = nullptr;
void bar_adapter()
{
    pX->bar();
}

int main()
{
    X x; // Some object I want to invoke the member function bar() on...

    pX = &x; // Set the global pointer and invoke the function...
    function_taking_a_function_pointer(bar_adapter);
}

If you want, you can make this slightly more flexible by turning bar_adapter into a function template, and passing the pointer-to-member-function as a template argument:

template<typename T, void (T::*mf)()>
void adapter()
{
    (pX->*mf)();
}

Here is how you would use it:

#include <iostream>

struct X
{
    void foo() { std::cout << "X::foo()" << std::endl; }
    void bar() { std::cout << "X::bar()" << std::endl; }
};

void function_taking_a_function_pointer(void (*f)())
{
    // Do something...
    f();
}

X* pX = nullptr;

template<typename T, void (T::*mf)()>
void adapter()
{
    (pX->*mf)();
}

int main()
{
    X x; // Some object I want to invoke the member function bar() on...

    pX = &x; // Set the global pointer and invoke the function(s)...

    function_taking_a_function_pointer(adapter<X, &X::foo>);
    function_taking_a_function_pointer(adapter<X, &X::bar>);
}

Finally, here is a live example.

2
votes

Each class member function has an implicit first parameter that is the this pointer, so your method in fact is not with void paramter list - it takes one parameter-- the instance it is invoked on.

0
votes

You can use boost::function<> or boost::bind<> to point to a class member function:

# include <boost/function.hpp>
# include <boost/bind.hpp>
class FunctionClass {
    private:
       double a_;
    public:
       FunctionClass (const double & a): a_(a ){}
       double multWithA (const double & x) const { return a_*x;}
       double operator ()(const double & x) const { return a_*x;}
};

FunctionClass myClass (2.0);
double x = 12.0;
boost :: function <double (FunctionClass *, double)> funcPtr , funcPtr1;
funcPtr =& FunctionClass :: multWithA;
funcPtr1 =& FunctionClass :: operator ();

std :: cout << myClass . multWithA (x) << std :: endl;
std :: cout << funcPtr (& myClass ,x) << std :: endl;
std :: cout << funcPtr1 (& myClass ,x) << std :: endl;

// Bind the function with the class instance
boost :: function <double (double)> funcPtrNew ;
funcPtrNew = boost :: bind (funcPtr ,& myClass ,_1);
std :: cout << funcPtrNew (x) << std :: endl;