简体   繁体   English

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

[英]A function that returns a function pointer for functions of different return types

The context of this question revolves around hard typed genetic programming.这个问题的背景围绕着硬类型遗传编程。

I would like to return a function pointer from a function but these functions pointers point to functions with different return types.我想从函数返回一个函数指针,但这些函数指针指向具有不同返回类型的函数。 In another stack overflow question ( Function Pointers with Different Return Types C ) a return type of union was suggested however I am struggling with the implementation.在另一个堆栈溢出问题( 具有不同返回类型 C 的函数指针)中,建议使用联合的返回类型,但是我正在努力实现。

I am fairly new to C++ so please forgive my ignorance if it shows.我对 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;
}

I expect (or rather would like) this to print the address of the function Add我期望(或者更确切地说是希望)这会打印函数 Add 的地址

TL;DR version: I think you may be trying to hammer a solution into fitting a problem . TL;DR 版本:我认为您可能正在尝试敲定解决方案以解决问题 Consider using something like the Visitor pattern to decouple the problem so that you don't need to know the type of the data.考虑使用诸如访问者模式之类的东西来解耦问题,这样您就不需要知道数据的类型。

A union isn't a type. union不是一种类型。 It's a type of types, like a class or a struct .它是一种类型,如classstruct In order to use a return_type , you have to make an object that is a return_type .为了使用return_type ,您必须创建一个return_type对象。 That means这意味着

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

    return return_type;
}

needs to look more like需要看起来更像

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
}

Then you can然后你可以

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

The big problem with union s is knowing what is in them. union的一个大问题是知道它们里面有什么。 You can only safely use ffptr if ffptr was the last member set.如果ffptr是最后一个成员集,您只能安全地使用ffptr

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

will compile, but will not behave well at all when run.将编译,但在运行时根本不会表现良好。 What will happen is undefined, but odds are good that it won't be pretty.会发生什么是不确定的,但很有可能它不会很漂亮。

You have to be absolutely certain that the function stored in the union is the correct one.您必须绝对确定存储在联合中的函数是正确的。 If your compiler is up to date, you can use std::variant to help out here.如果您的编译器是最新的,您可以使用std::variant来提供帮助。 It will at least tell you you're headed in the wrong direction by throwing an exception它至少会通过抛出异常告诉你你正朝着错误的方向前进

#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;
}

But at the end of the day it's still not all that useful.但在一天结束时,它仍然不是那么有用。 I think you may find the Visitor pattern or one of its friends more helpful.我认为您可能会发现访问者模式或其一位朋友更有帮助。

You were close.你很接近。 Be careful not to conflate the declaration of the (union) type name and the function return value.注意不要混淆(联合)类型名称的声明和函数返回值。 Since you want to reference pointer address, I added a void* to your union (fpaddr), so you can clearly identify that you are printing an address.由于您要引用指针地址,因此我在您的联合 (fpaddr) 中添加了一个 void*,因此您可以清楚地识别出您正在打印一个地址。 Note that your fptr("Add") returned the union, and you needed to disambiguate which interpretation of the union you wanted.请注意,您的 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;
}

I'm not quite sure what the ultimate goal is but here's how you can make the above compile and print the function address (printing of a plain Add added for comparison):我不太确定最终目标是什么,但这里是如何使上述编译并打印函数地址(打印Add的普通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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM