2014-08-29 2 views
0

У меня есть следующий код: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) как-то возможно?

+0

«multimethod» Предполагаю, вы имеете в виду полиморфный литой? Вы пришли с фонаря Clojure? –

+0

@ Мультимедиа @SirDigbyChickenCaesar - это языковое агностическое понятие (aka multiple dispatch) – sehe

+0

Независимо от того, нет ли способа определить (в системе типа C++, по крайней мере), независимо от того, является ли какая-либо произвольная INSTANCE класса производным или базовым классом в COMPILE раз после конкретизации. –

ответ

2

Вы можете использовать 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)

+0

Я хочу избежать использования динамического броска. – user152508

+0

dynamic_cast работает в RUN-TIME не во время компиляции. –

+3

Почему вы хотите аннулировать его? Это хорошая причина для его использования. –

0

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

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

Live example

+0

Почему вывод из' Args ... '? И вы можете передать любой несвязанный тип, который имеет метод «visit», включая то, что вообще не происходит от «A». – WhozCraig

0

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

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