2012-06-14 25 views
16

異なる数の引数を持つ関数に関数ポインタを割り当てる方法を理解しようとしています。C++:関数の引数の数が可変の関数へのポインタ

私は条件付きのステートメントとしていくつかの異なる関数をとるwhileループを持っているので、同じコードで複数のwhileループを書くのではなく、関数ポインタを持っていたいと思います。すべての関数の形式はbool f(...)です。

int a, b, c, d; 
MyClass* my_class; 

typedef bool (MyClass::*my_fun_t)(); 
my_fun_t my_fun; 

if (condition1) 
    my_fun = &MyClass::function_one(); 
else if (condition2) 
    my_fun = &MyClass::function_two(a, b); 
else if (condition3) 
    my_fun = &MyClass::function_three(a, b, c); 
else if (condition4) 
    my_fun = &MyClass::function_four(a, b, c, d); 

while ((my_class->*my_fun)()) 
{ ... } 

ここでは、関数が異なるシグネチャを持つため、これは明らかに機能しません。それはすべて同様の方法で動作させることは可能ですか?私が見なければならない何かのFunctoidsですか?

+0

引数の数がわからない場合は、その関数ポインタをどのように適用するのか分かりますか? – mfontanini

+0

関数ポインタへの代入構文が無効であることに注意してください。*関数を呼び出し、結果を取得し、その一時記憶領域へのポインタを取得し、事前に宣言した関数ポインタに*を割り当てます。 –

+0

ええ、私はそれがかなり有効な構文ではないことを知っています。それはちょうどアイデアを示す。 – jaho

答えて

7

std::function<>std::bind()を使用できます。

#include <functional> 

using std::placeholders::_1; 

typedef std::function<bool(MyClass&)> my_fun_t; 
my_fun_t my_fun; 

if (condition1) 
    my_fun = std::bind(&MyClass::function_one, _1); 
else if (condition2) 
    my_fun = std::bind(&MyClass::function_two, _1, a, b); 
else if (condition3) 
    my_fun = std::bind(&MyClass::function_three, _1, a, b, c); 
else if (condition4) 
    my_fun = std::bind(&MyClass::function_four, _1, a, b, c, d); 

while (my_fun(my_class)) { ... } 

これらは、C++ 11を使用することを前提としています。 C++ 11は使用できませんが、TR1を使用できる場合は、std::をすべてstd::tr1::に置き換えてください。 Boost implementationもあります。

+1

優秀、ありがとう。私はC++ 11を使うことができません。私はとにかく使用していますブースト以上のtr1を好む理由は何ですか? – jaho

+1

@Marian TR1は標準ライブラリに組み込まれていますが、boostはそうではありません。 – kennytm

1

私は、関数ポインタを異なる数の引数を持つ関数に割り当てる方法を理解しようとしています。

できません。ファンクションポインタは、に対応しています。ファンクションシグニチャです。これは完全に論理的です。そのような関数をどのように呼び出すのでしょうか? (はい、Cは宣言で関数の数を指定せずに関数を呼び出すことができますが、C++では機能しません)

Functoidsは私が見なければならないものですか?

一般的にはいですが、この問題は解決しません。

+0

しかし、可変引数を持つ関数の 'シグネチャ'はまだ一意です。 '...'可変引数部分は、少なくとも関数実装の中で使用される 'va_list'のカモフラージュです。関数ポインタを介してそのような関数を呼び出すと、そのような関数を(変数の引数のリストを使って)通常の方法で呼び出すこととは何の違いもありません。 –

+0

@ g-makulik可変引数は機能しますが、それは特定のシグネチャです。異なる関数シグネチャへのバインディングと同じではありません。 –

+0

ああ、私はあなたのポイントを参照してください!しかしOPは明白に(私が彼の「疑似コード」を間違って読んでいるかもしれない)綴りは言及していませんでした。インタフェース定義(ポリモーフィズム)を使用すると、OPが望んでいる(意図された)ものを達成することはまだ可能かもしれません。 –

3

std::function、多形関数オブジェクト、およびstd::bindは、引数を他のファンクタのパラメータにバインドすることによって関数オブジェクトを作成します。

C++ 11を使用できない場合、boost::functionboost::bindは同等ですが、少し制限があります。

std::function<bool()> my_fun; 

if (condition1) 
    my_fun = std::bind(&MyClass::function_one, my_class); 
else if (condition2) 
    my_fun = std::bind(&MyClass::function_two, my_class, a, b); 
else if (condition3) 
    my_fun = std::bind(&MyClass::function_three, my_class, a, b, c); 
else if (condition4) 
    my_fun = std::bind(&MyClass::function_four, my_class, a, b, c, d); 

while (my_fun()) 
{ ... } 
+1

C++ 11を使用できる場合は、ラムダ関数を使用して、その変数を囲むレキシカルスコープから引き出すこともできます。どちらが好きなのか、私は推測します。 – user268396

+0

@ user268396:おそらく。当分の間、私はラムダをサポートしていないコンパイラがついているので、私はそれらについてあまり知らない。 –

+0

ブーストソリューションが私のために働いています。ありがとうございました。 – jaho

4

は、これが私の作品:

#include <iostream> 
#include <cstdarg> 

using namespace std; 

class MyInterface 
{ 
public: 
    virtual bool func(int argc, ...) = 0; 
}; 

class MyImpl : public MyInterface 
{ 
public: 
    virtual bool func(int argc, ...); 
}; 

bool MyImpl::func(int argc, ...) 
{ 
    va_list varargs; 
    va_start(varargs,argc); 
    cout << "Arguments passed:" << endl; 
    for(int i = 0; i < argc; ++i) 
    { 
     // expect double values 
     double val = va_arg(varargs,double); 
     cout << val << endl; 
    } 
    va_end(varargs); 
    return true; 
} 

typedef bool (MyInterface::*MyFunc)(int, ...); 

int main() { 

    MyImpl impl; 
    MyInterface* interface = &impl; 
    MyFunc pfunc = &MyInterface::func; 

    if(!(interface->*pfunc)(2,double(3.14),double(2.72))) 
    { 
     return 1; 
    } 
    return 0; 
} 

出力:

Arguments passed: 
3.14 
2.72 

明らかにあなたが宣言し、変数の引数を使用して(member-)関数の関数ポインタを使用することができます。

関連する問題