函数指针联合

时间:2018-03-19 18:13:28

标签: c++ c++11

我有一个具有不同成员函数签名的类。根据一些要求(具体来说是为了优化执行时间),我需要在特定时间调用上述方法。我打算创建一个以下类型的结构:

#include <iostream>

class A
{
   public:
      void Show() {std::cout << "Called 0" << std::flush << std::endl;}
      int Show1() {std::cout << "Called 1" << std::flush << std::endl;}
      double Show2(char z) {std::cout << "Called 2" << std::flush << std::endl;}
      float Show3(int op, float x) {std::cout << "Called 3" << std::flush << std::endl;}
};

struct details
{
   int type ; /* methods to be called resp : 0 =Show,1=Show1,2=Show2,3=Show3*/
   union 
   {
      void (A::*fn)();
      int (A::*fn1)();
      double (A::*fn2)(char z);
      float (A::*fn3)(int op, float x);
   }fnptr;
};

int main()
{
   struct details d1 [4] ;
   d1[0].type = 0;
   d1[0].fnptr.fn = &A::Show;
   A a1;
   (a1.*(d1[0].fnptr.fn))();
   d1[0].type = 1;
   d1[0].fnptr.fn1 = &A::Show1;
   (a1.*(d1[0].fnptr.fn1))();
   d1[0].type = 1;
   d1[0].fnptr.fn2 = &A::Show2;
   (a1.*(d1[0].fnptr.fn2))('a');
   d1[0].type = 4;
   d1[0].fnptr.fn3 = &A::Show3;
   (a1.*(d1[0].fnptr.fn3))(2,3.14);
}


MINGW64 /c/work
$ c++ try.cpp -std=c++11

MINGW64 /c/work
$ ./a.exe
Called 0
Called 1
Called 2
Called 3

但是我无法初始化数组:

struct details d1 [4] = {{0, &A::Show}, {1, &A::Show1}, {2, &A::Show2}, {3, &A::Show3}};

说明编译错误

int main()
{
struct details d1 [4] = {{0, &A::Show}, {1, &A::Show1}, {2, &A::Show2}, {3, &A::Show3}};
}

try.cpp: In function 'int main()':
try.cpp:26:87: error: cannot convert 'int (A::*)()' to 'void (A::*)()' in initialization
 struct details d1 [4] = {{0, &A::Show}, {1, &A::Show1}, {2, &A::Show2}, {3, &A::Show3}};
                                                                                       ^
try.cpp:26:87: error: cannot convert 'double (A::*)(char)' to 'void (A::*)()' in initialization
try.cpp:26:87: error: cannot convert 'float (A::*)(int, float)' to 'void (A::*)()' in initialization

如何正确初始化结构?

2 个答案:

答案 0 :(得分:4)

  

但是我无法初始化数组:

struct details d1 [4] = {{0, &A::Show}, {1, &A::Show1}, {2, &A::Show2}, {3, &A::Show3}};

使用该语法初始化union时,该值必须与其第一个成员对应。在您的情况下,第一个成员是fn,其类型为void (A::*)()

该行相当于:

 struct details d1 [4] = {{0}, {1}, {2}, {3}};
 d1[0].fn = &A::Show;
 d1[1].fn = &A::Show1;
 d1[2].fn = &A::Show2;
 d1[3].fn = &A::Show3;

这解释了编译器错误。

Documentation from the standard

  

当使用大括号括起初始化程序初始化union时,大括号应仅包含union的第一个非静态数据成员的initializer子句。 [示例:

union u { int a; const char* b; };
u a = { 1 };
u b = a;
u c = 1;                        // error
u d = { 0, "asdf" };            // error
u e = { "asdf" };               // error
     

- 结束示例]

答案 1 :(得分:4)

目前,在C ++中,当联合为aggregate initialized时,只会初始化第一个非静态数据成员(可以是,或)。你无法解决这个问题。

好消息是,从C++20开始,您将能够select an active member during aggregate initialization。所以,这种语法应该可以在几年内完成。 : - )

details d1 [4] = {{0, {.fn = &A::Show}}, {1, {.fn1 = &A::Show1}}, {2, { .fn2 = &A::Show2}}, {3, { .fn3 = &A::Show3}}};