8

クラス関数(割り込みサービスルーチン)を使おうとしていますが、

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

次のタイプの入力の機能を使用してArduino割り込みピンに接続しますが、それは機能しません。

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

どうすればこれを実現できますか?割り込みサービスルーチン(ISR)はプライベートオブジェクトデータにアクセスする必要があるため、クラスの外部で関数を作成することはできません。

私のコンパイラエラー:

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

注:クラス内で解決策を探しています。解決策を示したり、不可能であることを示したりする回答を受け入れます。

4

3 に答える 3

7

関数がそうでない場合static、非メンバー関数ポインターを受け入れる関数に入力で渡すことはできません。

非メンバー関数には、メンバー関数が呼び出されているオブジェクトを指す最初のパラメーターとしてstaticの暗黙のポインターがあると考えてください。ClassName

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
}

ここではstd::bind()、結果が関数ポインターに変換できないため、機能しません。ラムダは関数ポインターに変換できますが、キャプチャーされていない場合に限ります(ここでのラムダは、メンバー関数を呼び出すためにオブジェクトをキャプチャーする必要があります)。

したがって、唯一の(醜い)回避策は、グローバルポインタ変数を介して利用可能なオブジェクトのメンバー関数を呼び出すグローバルアダプタ関数を使用することです。関数を呼び出す前に、グローバルポインタ変数が設定されます。

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);
}

bar_adapter必要に応じて、関数テンプレートに変換し、メンバー関数へのポインターをテンプレート引数として渡すことで、これを少し柔軟にすることができます。

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

使用方法は次のとおりです。

#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>);
}

最後に、これが実際の例です。

于 2013-03-24T14:31:33.653 に答える
2

各クラスメンバー関数には、ポインターである暗黙の最初のパラメーターがあるthisため、実際には、メソッドにはvoidパラメーターリストがありません。1つのパラメーターを取ります。これは、呼び出されるインスタンスです。

于 2013-03-24T14:31:15.640 に答える
0

boost::function<>またはを使用boost::bind<>して、クラスメンバー関数を指すことができます。

# 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;
于 2013-03-24T14:35:33.320 に答える