简体   繁体   English

是否可以声明指向具有未知(在编译时)返回类型的函数的指针

[英]Is it possible to declare a pointer to a function with unknown (at compile time) return type

I have a class A in which I want to have a pointer to a function as data member: 我有一个class A ,我希望有一个指向函数的指针作为数据成员:

class A
{
  protected:
    double (*ptrToFunction) ( double );

  public:
  ...
  //Setting function according to its name
  void SetPtrToFunction( std::string fName );
};

But what if I want ptrToFunction to be sometimes double and sometimes - int , to have something like: 但是如果我希望ptrToFunction有时是double ,有时候 - int ,有类似的东西:

//T is a typename
T(*ptrToFunction) ( double );

How should I declare it in this case? 在这种情况下我该如何申报呢?

A discriminated union can do that for you: 受歧视的工会可以为您做到这一点:

class A
{
  template<T>
  using cb_type = T(double);

  protected:
     enum {IS_INT, IS_DOUBLE} cb_tag;
     union {
       cb_type<int>    *ptrToIntFunction;
       cb_type<double> *ptrToDoubleFunction;
     };

  public:
  ...
  // Setting function according to its name
  void SetPtrToFunction( std::string fName );
};

A more general and elegant solution for a discriminated union can be applied with std::variant in C++17, or boost::variant for earlier standard revisions. 对于区分联合的更通用和优雅的解决方案可以应用于C ++ 17中的std::variant ,或者用于早期标准修订的boost::variant


Alternatively, if you want to completely ignore the return type, you can convert the member into std::function<void(double)> and benefit from type erasure. 或者,如果要完全忽略返回类型,可以将成员转换为std::function<void(double)>并从类型擦除中受益。 The Callable concept will see the call via pointer converted into static_cast<void>(INVOKE(...)) and discard the return value, whatever it is. Callable概念将通过指针将调用转换为static_cast<void>(INVOKE(...))并丢弃返回值,无论它是什么。

To illustrate : 举例说明

#include <functional>
#include <iostream>

int foo(double d)  { std::cout << d << '\n'; return 0; }

char bar(double d) { std::cout << 2*d << '\n'; return '0'; }

int main() {
    std::function<void(double)> cb;

    cb = foo; cb(1.0);

    cb = bar; cb(2.0);

    return 0;
}

And finally, if you do care about the return value but don't want to store a discriminated union. 最后,如果您确实关心返回值,但又不想存储受歧视的联合。 Then knowing about unions and the behavior of std::function , you can combine the above two approaches. 然后了解联合和std::function的行为,你可以结合上面两种方法。

Like this 像这样

#include <functional>
#include <iostream>
#include <cassert>

int    foo(double d) { return d; }

double bar(double d) { return 2*d; }

struct Result {
    union {
        int    i_res;
        double d_res;
    };
    enum { IS_INT, IS_DOUBLE } u_tag;

    Result(Result const&) = default;
    Result(int i)  : i_res{i}, u_tag{IS_INT} {}
    Result(double d) : d_res{d}, u_tag{IS_DOUBLE} {}

    Result& operator=(Result const&) = default;
    auto& operator=(int i)
    { i_res = i; u_tag = IS_INT;    return *this; }
    auto& operator=(double d)
    { d_res = d; u_tag = IS_DOUBLE; return *this; }
};

int main() {
    std::function<Result(double)> cb;

    cb = foo;
    auto r = cb(1.0);
    assert(r.u_tag == Result::IS_INT);
    std::cout << r.i_res << '\n';

    cb = bar;
    r = cb(2.0);
    assert(r.u_tag == Result::IS_DOUBLE); 
    std::cout << r.d_res << '\n';

    return 0;
}

If your class doesn't have a template, as in your example, you could do this: 如果您的班级没有模板(如您的示例中所示),则可以执行以下操作:

template <class T>
struct myStruct
{
  static T (*ptrToFunction)(double);
};

It looks that you are using dlsym / GetProcAddress to get the functions address. 看起来您正在使用dlsym / GetProcAddress来获取函数地址。

In this case, you need at least 2 call sites to disambiguate the call, as the CPU actually does different things for each of these calls. 在这种情况下,您需要至少2个呼叫站点来消除呼叫的歧义,因为CPU实际上为每个呼叫执行了不同的操作。

enum ReturnType { rtInt, rtDouble };
void SetPtrToFunction( std::string fName , enum ReturnType typeOfReturn );

struct Function {
   enum ReturnType rt;
   union {
          std::function< int(double) > mIntFunction;
          std::function< double(double) > mDoubleFunction;
   } u;
} mFunction;

So the function would need to be instantiated with a known return type, and then this used with some tagged union to get the correct function call. 因此,需要使用已知的返回类型对函数进行实例化,然后将其与某些标记的union一起使用以获取正确的函数调用。

  int A::doCall( double value ) {
      if( mFunction.rt == rtInt ) {
          int result = mFunction.mIntFunction( value );
      } else if( mFunction.rt == rtDouble ) {
          double result = mFunction.mDoubleFunction( value );
      }
  }

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

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