【问题标题】:C++: Function pointer to functions with variable number of argumentsC ++:指向具有可变数量参数的函数的函数指针
【发布时间】:2012-06-17 17:45:12
【问题描述】:

我正在尝试找出一种方法来将函数指针分配给具有不同数量参数的函数。

我有一个 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 是我应该看的东西吗?

【问题讨论】:

  • 如果你不知道它需要多少个参数,你怎么知道如何应用该函数指针?
  • 请注意,您分配给函数指针的语法无论如何都是无效的,您正在 调用 函数,获取结果,获取指向其临时存储的指针,然后分配 那个指向你事先声明的函数指针。
  • 是的,我知道这不是一个有效的语法。它只是展示了这个想法。

标签: c++ function function-pointers member-function-pointers


【解决方案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)) { ... }

这些假设您将使用 C++11。如果不能使用 C++11 但可以使用 TR1,请将所有 std:: 替换为 std::tr1::。还有一个Boost implementation

【讨论】:

  • 太好了,谢谢。我不能使用 C++11。有什么理由更喜欢 tr1 而不是 boost(无论如何我都在使用)?
  • @Marian 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

显然,您可以使用可变参数为(成员)函数声明和使用函数指针。

【讨论】:

    【解决方案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()) 
    { ... }
    

    【讨论】:

    • 如果您可以使用 C++ 11,那么您也可以使用 lambda 函数并从封闭的词法范围中提取变量。我猜你喜欢哪个。
    • @user268396:可能。目前,我被一个不支持 lambdas 的编译器困住了,所以我对它们了解不多。
    【解决方案4】:

    我正在尝试找出一种方法来将函数指针分配给具有不同数量参数的函数。

    你不能。函数指针特定于 one 函数签名。这完全合乎逻辑:你将如何调用这样的函数? (是的,C 允许调用函数而不在其声明中指定函数有多少参数,但这在 C++ 中不起作用,因为它颠覆了类型系统。)

    functoid 是我应该看的东西吗?

    通常是的,但他们没有解决这个问题。

    【讨论】:

    • 嗯,但只是具有可变参数的函数的“签名”仍然是唯一的,不是吗? '...' 变量参数部分至少只是函数实现中使用的 'va_list' 的伪装。通过函数指针调用这样的函数不会(不应该)与以通常的方式调用这样的函数(使用变量列表)有所不同。
    • @g-makulik 变量参数有效,但这是一个特定的签名,它与绑定到不同的函数签名不同。
    • 啊,我明白你的意思了!但是 OP 没有明确提到绑定(可能是我读错了他的“伪”代码)。使用接口定义(多态性)可能仍然可以实现 OP 想要的(预期的)。
    猜你喜欢
    • 2011-11-12
    • 1970-01-01
    • 2017-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-30
    相关资源
    最近更新 更多