为不同返回类型的函数返回函数指针的函数

时间:2019-06-14 22:16:52

标签: c++ pointers union

这个问题的背景围绕着硬类型基因编程。

我想从一个函数返回一个函数指针,但是这些函数指针指向具有不同返回类型的函数。在另一个堆栈溢出问题(Function Pointers with Different Return Types C)中,提出了联合的返回类型,但是我正在为实现而苦苦挣扎。

我对C ++还是很陌生,所以请原谅我的无知。

#include <iostream>
#include <string>

float Add(float a, float b) { return a + b; }
bool IfElse(bool a) { if (a) { return true; } else { return false; }; }

union return_type
{
    float(*ffptr)(float, float);
    bool(*bfptr)(bool);
};  

union fptr(std::string OPERATION) {
    if (OPERATION == "Add") {
        return_type.ffptr = Add;
    } else if (OPERATION == "IfElse") {
        return_type.bfptr = IfElse;
    }

    return return_type;
}

int main() {
    std::cout << fptr("Add") << std::endl
    return 0;
}

我希望(或更确切地说,希望这样做)打印添加功能的地址

3 个答案:

答案 0 :(得分:4)

TL; DR版本:我认为您可能正在尝试hammer a solution into fitting a problem。考虑使用类似Visitor pattern的方法来解耦问题,这样您就不必知道数据的类型。

union不是类型。 It's a type of types, like a class or a struct。为了使用return_type,您必须制作一个return_type的对象。那是

union fptr(std::string OPERATION) {
    if (OPERATION == "Add") {
        return_type.ffptr = Add;
    } else if (OPERATION == "IfElse") {
        return_type.bfptr = IfElse;
    }

    return return_type;
}

需要看起来更像

return_type fptr(std::string OPERATION) {
    return_type result; // make a return_type object
    if (OPERATION == "Add") {
        result.ffptr = Add; // set a member of the object
    } else if (OPERATION == "IfElse") {
        result.bfptr = IfElse;
    }

    return result; // return the object
}

那么您可以

int main() {
    std::cout << fptr("Add").ffptr(10,20) << std::endl; // call the stored function
    return 0;
}

union的最大问题是知道其中的内容。如果ffptr是最后一个成员集,则只能安全使用ffptr

int main() {
    std::cout << fptr("Add").bfptr(true) << std::endl;
    return 0;
}

可以编译,但运行时表现不佳。会发生什么是不确定的,但是很有可能它不会很漂亮。

您必须绝对确定联合中存储的功能是正确的。如果您的编译器是最新的,请you can use std::variant在此处提供帮助。至少会抛出异常,告诉您您的方向错误

#include <iostream>
#include <string>
#include <variant>

float Add(float a, float b) { return a + b; }
bool IfElse(bool a) { if (a) { return true; } else { return false; }; }

using return_type = std::variant<float (*)(float a, float b), bool (*)(bool a)>;

return_type fptr(std::string OPERATION) {
    return_type result;
    if (OPERATION == "Add") {
        result = Add;
    } else if (OPERATION == "IfElse") {
        result = IfElse;
    }

    return result;
}

int main() {
    std::cout << std::get<float (*)(float a, float b)>(fptr("Add"))(10,20) << std::endl;
    try
    {
        std::cout << std::get<bool (*)(bool a)>(fptr("Add"))(true) << std::endl;
    }
    catch (const std::bad_variant_access& e)
    {
        std::cout << e.what() << std::endl;
    }
        return 0;
}

但是最终还是没有那么有用。我认为您可能会发现Visitor pattern或它的一个朋友更有用。

答案 1 :(得分:2)

你很近。 注意不要将(联合)类型名称的声明和函数返回值混淆。由于您要引用指针地址,因此我在您的联合(fpaddr)中添加了一个void *,因此您可以清楚地识别出您正在打印地址。请注意,您的fptr(“ Add”)返回了联合,并且您需要消除对所需联合的解释的歧义。

#include <iostream>
#include <string>

float Add(float a, float b) { return a + b; }
bool IfElse(bool a) { if (a) { return true; } else { return false; }; }

//typedef //in C you would use 'typedef'
union fp_return_t
{
    float(* ffptr )(float, float);
    bool(* bfptr )(bool);
    void* fpaddr;
}; //fp_return_t; //in C you would give the name here

fp_return_t fptr(std::string OPERATION) {
    fp_return_t fp_return;
    if (OPERATION == "Add") {
        std::cout << "Add:" << (void*) Add << std::endl;
        fp_return.ffptr = Add;
    } else if (OPERATION == "IfElse") {
        std::cout << "IfElse:" << (void*) IfElse << std::endl;
        fp_return.bfptr = IfElse;
    }

    return fp_return;
}

int main() {
    std::cout << fptr("Add").fpaddr << std::endl;
    return 0;
}

答案 2 :(得分:1)

我不确定最终目标是什么,但是您可以通过以下方法进行上述编译并打印函数地址(打印出普通的Add以供比较):

#include <iostream>
#include <string>

float Add(float a, float b) { return a + b; }
bool IfElse(bool a) { return a; }

union return_type
    {
    float(*ffptr)(float, float);
    bool(*bfptr)(bool);
    };  

union return_type fptr(std::string OPERATION) {
    union return_type r;
    if (OPERATION == "Add") {
        r.ffptr = Add;
    } else if (OPERATION == "IfElse") {
        r.bfptr = IfElse;
    }

    return r;
}

int main()
{
    /*the void*-cast is technically nonportable but it's hard to
      print fn-pointers portably*/
    std::cout << reinterpret_cast<void*>(Add) << '\n';

    /*you should know which union member is active: */
    std::cout << reinterpret_cast<void*>(fptr("Add").ffptr) << '\n';
    /*^should be the same address*/
    return 0;
}