문제

Can I somehow use Curiously Recurring Template Pattern (CRTP) with array?
What I want? I want array of classes that have some foo function. And call it for all objects in array. Like so:

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();

P.S. I read, also, about AutoList pattern. But it seems it have nothing to do with my problem.

도움이 되었습니까?

해결책 2

You can use another (non-templated) base and a virtual call, like this:

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";
    }
};

And use it like this:

VirtualBase * a [] = {new A(), new B()};

a[0]->call ();
a[1]->call ();

Note that to have polymorphism, you need to work with pointers or references (which is one of the problems with your code, because you are trying to put instances themselves into an array.)

Also, note the name change between call and real_call.

And don't forget to delete the instances; for example like this:

for (auto e : a) delete e;

or you can use std::unique_ptr<>, but the initialization of the array will be more verbose.


Update about virtual calls, in response to comments:

If you want to be able to dispatch to different methods determined at runtime, then you have to to use some kind of indirection. You won't be able to let the compiler bake in the call addresses at compile time (which is what happens with ordinary function calls and non-virtual method calls.)

One form of that indirection is using virtual methods; others are using function pointers, or even switch statements. There are other more exotic and less-used forms of call indirection too (e.g. runtime in-memory patching of addresses, etc.) but they are rarely worth the effort.

In short, if you want to have the flexibility of runtime dispatch, you'll have to pay the price.


Update with another sample: In response to comments on other answers, here's a small sample of CRTP used in conjunction with polymorphism. It's just an example, and not a good one, but I see no reason why they can't be used together.

다른 팁

You can't have an array

Base array[2];

since Base is not a class.

Base<A> and Base<B> are classes but the two are completely different classes, with no relationship between them.

Update

You could use something like what @yzt suggested but then that is hardly any more elegant than:

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 ();

The CRTP class doesn't need to be present at all.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top