C++ CRTP in array

C++ CRTP in array

本文关键字:array in CRTP C++      更新时间:2023-10-16

我能以某种方式使用奇怪的循环模板模式(CRTP)与数组吗?
我想要什么?我想要一个包含foo函数的类数组。并对数组中的所有对象调用它。像这样:

template<class Derived>
struct Base{
  void call(){
     static_cast<Derived*>(this)->call();
  }
};    
struct A : Base<A>{
    void call(){
        cout <<"A";
    }
};
struct B : Base<B>{
    void call(){
        cout <<"B";
    }
};
...
Base array[2] = {A(), B()};  // <-- here is my array
array[0].call();
array[1].call();

注:我也读过关于自动列表模式的文章。但这似乎与我的问题无关。

不能有数组

Base array[2];

因为Base不是一个类。

Base<A>Base<B>是两个完全不同的类,两者之间没有关系。

你可以使用@yzt建议的东西,但是那样的话,几乎不会比:

更优雅
struct Base {
    virtual void call () = 0;
};

struct A : Base {
    void call () {
        cout << "A";
    }
};
struct B : Base {
    void call () {
        cout << "B";
    }
};
Base* a [] = {new A(), new B()};
a[0]->call ();
a[1]->call ();

根本不需要出现CRTP类

您可以使用另一个(非模板化的)基和虚调用,如下所示:

struct VirtualBase {
    virtual void call () = 0;
};
template <class Derived>
struct Base : VirtualBase {
    virtual void call () override {
        static_cast<Derived*>(this)->real_call ();
    }
};    
struct A : Base<A> {
    void real_call () {
        cout << "A";
    }
};
struct B : Base<B> {
    void real_call () {
        cout << "B";
    }
};

并像这样使用:

VirtualBase * a [] = {new A(), new B()};
a[0]->call ();
a[1]->call ();

请注意,要具有多态性,您需要使用指针或引用(这是代码中的问题之一,因为您试图将实例本身放入数组中。)

另外,请注意callreal_call之间的名称更改。

不要忘记delete实例;例如:

for (auto e : a) delete e;

或者您可以使用std::unique_ptr<>,但是数组的初始化将更加冗长。


更新关于虚拟调用的信息,以响应:

如果你想在运行时分派给不同的方法,那么必须使用某种间接方式。您将无法让编译器在编译时嵌入调用地址(这是普通函数调用和非虚方法调用所发生的情况)

这种间接的一种形式是使用虚方法;其他人则使用函数指针,甚至是switch语句。还有其他更奇特和较少使用的间接调用形式(例如运行时内存中的地址补丁等),但它们很少值得付出努力。

简而言之,如果你想拥有运行时调度的灵活性,你必须付出代价。


用另一个示例更新:为了回应对其他答案的评论,这里有一个与多态性结合使用的CRTP的小示例。这只是一个例子,并不是一个很好的例子,但我认为没有理由为什么它们不能一起使用。