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

par*_*xod 26 c++ function-pointers function

我有一个class A我希望有一个指向函数的指针作为数据成员:

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

  public:
  ...
  //Setting function according to its name
  void SetPtrToFunction( std::string fName );
};
Run Code Online (Sandbox Code Playgroud)

但是,如果我想ptrToFunction有时候double,有时甚至int是这样的话:

//T is a typename
T(*ptrToFunction) ( double );
Run Code Online (Sandbox Code Playgroud)

在这种情况下我该如何申报呢?

Sto*_*ica 25

一个区分联合可以为你做的:

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 );
};
Run Code Online (Sandbox Code Playgroud)

对于区分联合的更通用和优雅的解决方案可以std::variant在C++ 17中应用,或者boost::variant用于早期的标准修订.


或者,如果要完全忽略返回类型,可以将成员转换std::function<void(double)>为类型擦除并从中受益.该Callable概念将看到通过指针转换的调用static_cast<void>(INVOKE(...))并丢弃返回值,无论它是什么.

为了举例说明:

#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;
}
Run Code Online (Sandbox Code Playgroud)

最后,如果你关心的是返回值,但又不想存储受歧视的联合.然后了解工会和行为std::function,你可以结合上述两种方法.

像这样

#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;
}
Run Code Online (Sandbox Code Playgroud)

  • 不要介意,但要理解这一点有点复杂.很少的内联评论会有所帮助.`cb_tag`有什么用? (2认同)