2

我在一个类中有一批函数:

class Edges // Edges of a Rubik's cube
{
    // Stuff
    
    protected:
        // Edges movements
        void e_U();
        void e_D();
        void e_F();
        void e_B();
        void e_R();
        void e_L();
        
    // More stuff
};

一个新类继承了这个函数:

class Cube: public Edges // Rubik's cube class
{
    public: 
        void U(int); // U slice edges movement relative to spin
        
    // Stuff
}

所需函数的调用取决于一个数字,如下代码所示:

void Cube::U(int spin) // U slice movement for the given spin
{
    switch (spin)
    {
        case 0: e_U(); return;
        case 1: e_U(); return;
        case 2: e_U(); return;
        case 3: e_U(); return;
        case 4: e_D(); return;
        ...
        case 23: e_L(); return;
        default: return;
    }
}   

我想提高性能,所以我把函数放在一个数组中:

class Cube: public Edges // Rubik's cube class
{
    public: 
        void U(int); // U slice edges movement relative to spin
        
    // Stuff
    
    private:
    
        const static void (*(USlice[24]))(); // U slice edges movement relative to spin
        
    // More stuff
}

const void Cube::( (*(USlice[24]))() ) =
{ 
    e_U, e_U, e_U, e_U,
    e_D, e_D, e_D, e_D,
    e_F, e_F, e_F, e_F,
    e_B, e_B, e_B, e_B,
    e_R, e_R, e_R, e_R,
    e_L, e_L, e_L, e_L
};

所以 U 函数现在应该是这样的:

void Cube::U(int spin) // U slice movement for the given spin
{
    USlice[spin]();
}

我的问题是我找不到在类中声明函数数组的正确方法。我已经尝试了我能想到的一切(删除“const”和“static”语句,公开所有内容,...)

数组应该是“static”和“const”,成员是 24 个没有参数的“void”函数。

实际上我不知道在数组中声明函数是否会比使用 switch 语句更快,但我想检查一下。

谢谢。

4

3 回答 3

3

Actually, for only performance, you don't need to use array of function pointers.

There is no speed difference.
Using function pointers, it tooks 1 MOV operation in asm(about 2 DWORD), while using switch tooks 1~2 CMP or TEST operations(about 2-6 WORD, because there are only 6 unique functions in 24sets).

The errors you mentioned is that, values of array are the function pointers to protected member function - not global function.
This means, you have to think about 1st function parameter is *this which is invisible to c++ code.

于 2021-08-05T12:06:43.427 回答
2

您的问题的答案是e_U,e_D等都是成员函数,而不仅仅是普通函数,因此指向它们的指针类型是指向成员函数的指针。

您的数组的声明和用法如下所示:

class Cube : public Edges {
    // ...
    static void (Cube::* const USlice[24])();
};

void (Cube::* const Cube::USlice[24])() = {
    &Cube::e_U, &Cube::e_U, &Cube::e_U, &Cube::e_U,
    &Cube::e_D, &Cube::e_D, &Cube::e_D, &Cube::e_D,
    &Cube::e_F, &Cube::e_F, &Cube::e_F, &Cube::e_F,
    &Cube::e_B, &Cube::e_B, &Cube::e_B, &Cube::e_B,
    &Cube::e_R, &Cube::e_R, &Cube::e_R, &Cube::e_R,
    &Cube::e_L, &Cube::e_L, &Cube::e_L, &Cube::e_L
};

void Cube::U(int spin) {
    (this->*USlice[spin])();
}

或者,您可以将所有函数变成静态函数并使this参数显式(void e_U();-> static void e_U(Edges&);),并且可以将它们存储为函数指针


但是,带有数组的版本并没有特别优化。gcc 和 clang 仍然有很多开销来处理指向虚函数的指针。开关版本优化为(更好的)查找表和简单跳转到表中的值,就像你想要的那样。这种模式很容易优化成表格,所以你的编译器应该已经在这样做了。

请参阅此处进行反汇编:https ://godbolt.org/z/beaPYvzMY (开关 LUT 标记为.L4,显式指针到成员表标记为Cube::U_lookup(int)::table

于 2021-08-05T12:42:17.977 回答
2

您要保留在数组中的函数指针是指向Cube对象方法的指针。但是您想将该数组成员变量定义为静态变量。如您所知,无需任何类对象即可访问静态变量。所以,这是一个矛盾。

您可以像这样编写您的类,而无需将数组设为静态。

class Cube : public Edges // Rubik's cube class
{
public:
   Cube() :
      mFuncs{ 
         std::bind(&Cube::e_U, this),
         std::bind(&Cube::e_U, this),
         std::bind(&Cube::e_U, this), 
         std::bind(&Cube::e_U, this), 
         std::bind(&Cube::e_D, this),
         std::bind(&Cube::e_L, this) }
   {
   }

   void e_U() {}
   void e_D() {}
   void e_L() {}

   void U(size_t spin) // U slice edges movement relative to spin
   {
      if (spin < mFuncs.size())
      {
         mFuncs[spin]();
      }
      else
      {
         // report the error
      }
   }
protected:
   const std::vector<std::function<void()>> mFuncs;
// Stuff
};
于 2021-08-05T12:11:33.617 回答