web-dev-qa-db-ja.com

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)()) 
{ ... }

関数のシグネチャが異なるため、これは明らかに機能しません。同様の方法で機能させることは可能ですか?ファンクトイドは私が見なければならないものですか?

17
jaho

_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::_に置き換えます。 ブースト実装 もあります。

7
kennytm

これは私のために働きます:

#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

明らかに、変数引数を使用して(メンバー)関数の関数ポインターを宣言して使用できます。

5

あなたが欲しいstd::function、ポリモーフィック関数オブジェクト、およびstd::bind他のファンクターのパラメーターに引数をバインドすることにより、関数オブジェクトを作成します。

C++ 11を使用できない場合は、boost::functionおよびboost::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()) 
{ ... }
3
Mike Seymour

引数の数が異なる関数に関数ポインタを割り当てる方法を見つけようとしています。

できません。関数ポインタはone関数シグネチャに固有です。これは完全に論理的です。そのような関数をどのように呼び出しますか? (はい、Cは、関数が持つパラメーターの数を宣言で指定せずに関数を呼び出すことを許可しますが、これは型システムを破壊するため、C++では機能しません。)

ファンクトイドは私が見なければならないものですか?

通常はそうですが、この問題は解決しません。

1
Konrad Rudolph