C++ мультиметоды и определение времени компиляции

У меня есть следующий код:

class A{};
class B: public A{};
class C: public A{};

class MyVisitor
{
   public:
       void visit(B*);
       void visit(C*);
};

И тогда коллекция объектов A*, я хочу добиться следующего:

1)

MyVisitor visitor;
for(vector<A*>::iterator it = vec.begin(); it!= vec.end();it++)
     visitor->visit(a);

2) Как-то определить во время компиляции, если A* указывает на производный объект D, и дать ошибку компилятора, если MyVisitor::visit(D*) функции нет

Я знаю, что 1) достижимо с помощью некоторых мультиметодных реализаций, думаю, я могу найти некоторые реализации мультиметодов для C++ . Но 2) как-то возможно?

4 ответа

Решение

Может быть, вы хотите взглянуть на это: http://www.yorel.be/mm/, https://github.com/jll63/yomm11, http://www.codeproject.com/Articles/635264/Open-Multi-Methods-for-Cplusplus11-Part-1

Это реализация мульти-методов для C++, которая очень напоминает предложение Stroustrup & al. Это также быстро, это бьет двойную отправку.

Вы могли бы использовать dynamic_cast как это (внутри тела вашего for цикл), поскольку поведение должно изменяться во время выполнения (в соответствии с фактическим типом данных).

   ClassB* ba = dynamic_cast<ClassB*>(a);
   if (ba)
      visitor->visit(ba);
   ClassC* ca = dynamic_cast<ClassC*>(a);
   if (ca)
      visitor->visit(ca);

Может быть, ваш visit функции могут быть объявлены virtual (для тебя ClassD вещь).

В противном случае организуйте свои классы как дерево (не лес) классов, и у вас будет самый верхний корневой класс

  class Topmost {
     virtual int classnum() const;

и принять соглашение, что каждый неабстрактный класс дает свой уникальный classnum и т.д.... Или есть механизм метакласса (например, в Qt)

Вы можете применить шаблон посетителя полностью:

class B;
class C;

class IVisitor
{
public:
    void visit(B&) = 0;
    void visit(C&) = 0;
};

class A
{
    virtual ~A() = default;
    virtual void accept(IVisitor& v) = 0;
};

class B: public A{ void accept(IVisitor& v) override { v.visit(*this); } };
class C: public A{ void accept(IVisitor& v) override { v.visit(*this); } };

Вы можете попробовать что-то вроде этого.

#include <iostream>

class A
{
    virtual void visit() = 0;
};
class B: private A
{
public:
    void visit()
    {
        std::cout << __PRETTY_FUNCTION__ << "\n";
    }
};
class C: private A
{
public:
    void visit()
    {
        std::cout << __PRETTY_FUNCTION__ << "\n";
    }    
};

template <typename... Args>
class MyVisitor : public Args...
{
   public:
       template <typename T>
           void visit(T* t)
       {
           t->visit();
       }
};

int main()
{
    MyVisitor<B, C> visitor;
    B b;
    B* bp = &b;
    visitor.visit(bp);
    return 0;
}

Живой пример

Другие вопросы по тегам