【问题标题】:Properly implementing an array of class functions正确实现类函数数组
【发布时间】:2019-11-22 14:45:51
【问题描述】:

我想创建一个已知大小的类函数数组。为此,我尝试使用 typedef,但到目前为止还没有成功。 此外,一些函数不接受任何参数。 F(),但其他人确实如此。 G(int n),并且在 typedef 中,我不知道如何告诉它不接受某些参数(尝试 void 但它说它不是类型),并接受其他参数。

 class myClass
{
    // An array of void functions
    typedef void(myClass::*arrayOfFunctions)();

private:
    arrayOfFunctions array[3] = { &myClass::F, &myClass::G, &myClass::H };

    void F() { do stuff; }
    void G(int n) { do stuff involving n; }
    void H() { do stuff; }
};

我尝试过的: 我已经成功地在 main 中创建了一个 void 函数数组,没有涉及我可以在需要时调用的类,所以部分问题似乎是在一个类中实现它并使用它的类函数。

// This works:

typedef void(*arrayOfFunctions)();

void Action1()
{
    // stuff 1
}

void Action2()
{
    // stuff 2
}

void Action3()
{
    //stuff3
}

int main()
{
    arrayOfFunctions functionArray[] = { Action1, Action2, Action3 };

    // Call Action1
    functionArray[0]();

    return 0;
)

【问题讨论】:

  • 我只是好奇,你想用它实现什么?
  • 您不能这样做 - 所有数组元素必须具有相同的类型。 (在C++中,一个空的参数列表意味着“没有参数”。它相当于C中的参数列表(void)。)
  • // An array of void functions typedef void(myClass::*arrayOfFunctions)(); -- 更好的方法是让一个对象数组重载operator()。然后你可以有一个没有参数的函数,另一个有 3,另一个有 1,都具有不同的返回类型。使用函数指针的“老派”C 风格方式是有限的。
  • "我不知道如何告诉它不接受一些参数" - 你怎么知道你应该将参数传递给一些人?

标签: c++ arrays typedef class-method


【解决方案1】:

正如在 cmets 中提到的,直接不可能。您不能将不同类型的对象存储在同一个数组中。但是,有一些方法可以实现您想要的。如何到达那里很大程度上取决于细节。最近调用函数的时候需要知道要传递多少个参数。

在您的示例中,一种可能性是重构为只有没有参数的方法:

 class myClass {
    using memFun = void(myClass::*)();
    void set_n(int x) { n = x; }
private:
    memFun array[3] = { &myClass::F, &myClass::G, &myClass::H };    
    void F() { do stuff; }
    void G() { do stuff involving n; }
    void H() { do stuff; }
    int n;
};

我更改了别名的名称,因为它只是函数指针的类型而不是数组。 usingtypedef 更容易阅读(它遵循更常见的 x = something 风格)。

当您调用函数G 时,参数n 必须来自某个地方,因此您可以在迭代数组之前调用set_n,而不是直接传递它,然后调用所有不带参数的方法。

【讨论】:

    【解决方案2】:

    不清楚你想如何使用这样的数组。如果您在编译时知道元素索引,那么您可能会使用 std::tuple 和模板参数推导。例如:

    class my_class {
    public:
        template<std::size_t n, class... Args>
        decltype(auto) call_fn(Args&&... args) {
            constexpr auto ptrs = get_fn_pointers();
            return std::invoke(std::get<n>(ptrs), this, std::forward<Args>(args)...);
        }
    
    private:
        static constexpr auto get_fn_pointers() {
            return std::tuple(&my_class::f, &my_class::g, &my_class::h);
        }
    
        void f() { 
            std::cout << "f()\n"; 
        }
    
        void g(int n) { 
            std::cout << "g(" << n << ")\n";
        }
    
        int h() { 
            std::cout << "h() => "; 
            return 9102;
        }
    };
    
    int main() {
        my_class c;
        c.call_fn<0>();               // Output: f()
        c.call_fn<1>(2019);           // Output: g(2019)
        std::cout << c.call_fn<2>();  // Output: h() => 9102
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-13
      • 2021-01-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多