С++: указатель на функции с переменным числом аргументов - программирование
Подтвердить что ты не робот

С++: указатель на функции с переменным числом аргументов

Я пытаюсь выяснить способ уметь назначать указатель на функции с различным количеством аргументов.

У меня есть цикл 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)()) 
{ ... }

Теперь это явно не работает, потому что функции имеют разные подписи. Возможно ли, чтобы он работал аналогичным образом? Являются ли функтоиды чем-то, на что я должен смотреть?

4b9b3361

Ответ 1

Вы можете использовать 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)) { ... }

Предполагается, что вы будете использовать С++ 11. Если вы не можете использовать С++ 11, но можете использовать TR1, замените все std:: на std::tr1::. Существует также Boost реализация.

Ответ 2

Это работает для меня:

#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-) -функций, используя переменные аргументы.

Ответ 3

Вы хотите std::function, объект полиморфной функции и std::bind создавать объекты функции, связывая аргументы с параметрами других функторов.

Если вы не можете использовать С++ 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()) 
{ ... }

Ответ 4

Я пытаюсь выяснить способ, как можно назначить указатель на функции с различным количеством аргументов.

Вы не можете. Указатели функций относятся к одной сигнатуре функции. Это вполне логично: как бы вы вызвали такую ​​функцию? (Да, C позволяет вызывать функции без указания в их объявлении, сколько параметров имеет функция, но это не работает в С++, поскольку оно подрывает систему типов.)

Являются ли functoids чем-то, над чем я должен смотреть?

Как правило, да, но они не решают эту проблему.