Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Как найти базовый класса для данного класса


Автор: Empirik 29.6.2014, 21:12
Делаю свою реализацию паттерна Visitor. Точнее его подвида Static Visitor. Но есть одна проблема. Нужно, что бы если в посетителе нет класса для нужного метода, хотелось бы что бы посетитель находил метод с ближайшим предком для данного объекта и вызывал метод для него. Как решить эту задачу я пока не знаю. 

Задачу нахождения визитера под конкретный тип решаю при помощи макроса. 

Код

#define MAKE_VISITABLE \
    virtual void visit(CVisitor& visitor)const{\
    typedef decltype(*this) TThisConstRefernceType;\
    typedef std::remove_reference<TThisConstRefernceType>::type TThisTypeReference;\
    typedef std::remove_const<TThisTypeReference>::type TThisType; \
    static CVisitableClassInfo<TThisType> classMeta;\
    TVisitor<TThisType>* visitorOfType = dynamic_cast<TVisitor<std::remove_const<TThisType>::type>*>(&visitor);\
    if (visitorOfType)\
    {\
        visitorOfType->make_visit(*this); \
    }else\
    {\
    std::cout << "can't handle class " << typeid(*this).name() << " " << typeid(TThisType).name()<<std::endl; \
    }\
    }\
    virtual void visit(CVisitor& visitor){\
    typedef decltype(*this) TThisTypeReference; \
    typedef std::remove_reference<TThisTypeReference>::type TThisType; \
    TVisitor<TThisType>* visitorOfType = dynamic_cast<TVisitor<TThisType>*>(&visitor);\
    if (visitorOfType)\
    {\
    visitorOfType->make_visit(*this); \
    }\
    else\
    {\
    std::cout << "can't handle class " << typeid(*this).name() << " " << typeid(TThisType).name() << std::endl; \
    }\
    \
    }\
    template<typename CType> bool is_can_convert_to()const\
    {\
        typedef decltype(*this) TThisConstRefernceType; \
        typedef std::remove_reference<TThisConstRefernceType>::type TThisTypeReference; \
        typedef std::remove_const<TThisTypeReference>::type TThisType; \
        return std::is_base_of<CType, TThisType>::value;\
    }\


Как бы вы решили задачу нахождение визитера ближайшего родителя для данного класса? 

Автор: Lukkoye 30.6.2014, 22:15
Не совсем понятно, зачем и чего вы там ищете.

Если у вас есть и иерархия классов, и вам просто нужно времени компиляции определить доступен ли метод указанного имени и указанной сигнатуры, то вы можете воспользоваться моим SFINAE-детектором.

Для этого вам понадобится поддержка с++11


Мой детектор корректно умеет обрабатывать перегрузку функций-членов.
При этом учитывает что функция член может иметь квалификатор const.

Правила доступности - аналогичны правилам доступности методов в языке с++


Есть проблемы для компиляторов вижал студии (плохая поддержка стандарта с++11)
Подробности вы можете узнать здесь:
http://www.gamedev.ru/code/forum/?id=184871

http://ideone.com/ObElnu


Код

#include <iostream>
#include <type_traits>
 
using namespace std;
 
 
#define DETECTED_MEMBER(member_name)                                                      \
template<typename C, typename T>class has_##member_name                                   \
{                                                                                         \
    template<class U> static constexpr auto Check(U*) -> typename                         \
    std::is_same< decltype( std::declval<U>().member_name), T >::type;                    \
                                                                                          \
    template<typename> static constexpr std::false_type Check(...);                       \
    typedef decltype(Check<C>(0)) Result;                                                 \
public:                                                                                   \
    enum { eIS_NOCONST = 0 };                                                             \
    enum { eIS_CONST   = 0 };                                                             \
    enum { eIS_AVAILABLE = Result::value };                                               \
};                                                                                        \
template<class C,typename R, typename... Args>class has_##member_name<C, R(Args...)>      \
{                                                                                         \
    typedef R(C::*Method)(Args...);    typedef R(C::*CMethod)(Args...)const;              \
    template <class U> using NoConst = decltype(static_cast<Method> (&U::member_name));   \
    template <class U> using Const   = decltype(static_cast<CMethod>(&U::member_name));   \
                                                                                          \
    template<class U> static constexpr std::true_type  CheckNoConst( NoConst<U>*p );      \
    template<class>   static constexpr std::false_type CheckNoConst(...);                 \
    typedef decltype(CheckNoConst<C>(0)) NoConstResult;                                   \
                                                                                          \
    template<class U> static constexpr std::true_type  CheckConst( Const<U>*p);           \
    template<class>   static constexpr std::false_type CheckConst(...);                   \
    typedef decltype(CheckConst<C>(0)) ConstResult;                                       \
public:                                                                                   \
    enum { eIS_NOCONST = NoConstResult::value      };                                     \
    enum { eIS_CONST   = ConstResult::value        };                                     \
    enum { eIS_AVAILABLE = eIS_NOCONST | eIS_CONST };                                     \
};
 
#define is_available(class_name, member_type, member_name)         has_##member_name<class_name, member_type>::eIS_AVAILABLE
#define is_available_method(class_name, member_type, member_name)  has_##member_name<class_name, member_type>::eIS_NOCONST
#define is_available_cmethod(class_name, member_type, member_name) has_##member_name<class_name, member_type>::eIS_CONST
 
//------------------------------------------------------------------------------------
 
 
int g;
struct A  //<---- для эксперимента будем определять доступность методов и данных
{
    A():r(g){}
 
    void fooA(int);
    void fooA(int)const;
    void fooA();
    void fooA()const;
 
    int v;
    int& r;
    int a[10];
    int* p;
    int** pp;
private:
    void private_foo();
};
 
struct B : A   //<---- используем наследование, 
{              //что бы продемонстрировать определение доступности методов в базовых классах
    int v;
    int fooB(){ return 0; }
};
 

//указываем имена мемберов, доступность которых хотим определить
DETECTED_MEMBER(fooA);
DETECTED_MEMBER(fooB);
DETECTED_MEMBER(v);
DETECTED_MEMBER(r);
DETECTED_MEMBER(a);
DETECTED_MEMBER(p);
DETECTED_MEMBER(pp);
 
DETECTED_MEMBER(private_foo);
 
 
int main()
{
    //синтаксис:  is_available(  имя_класса ,  тип_мембера  , имя_мембера)
 
    //вернет true если мембер доступен, иначе - false
 
    //---- детектирование данных
    cout<< "is available int B.v ? "
        << is_available(B,int,v)     <<endl;
 
    cout<< "is available int& B.r ? "
        << is_available(B,int&,r)    <<endl;
 
    cout<< "is available int B.a[10] ? "
        << is_available(B,int[10],a) <<endl;
 
    cout<< "is available int* B.p ? "
        << is_available(B,int*,p)    <<endl;
 
    cout<< "is available int* B.pp ? "
        << is_available(B,int**,pp)  <<endl;
 
    //---- детектирование методов
    cout<< "is available void B.fooA(int) or void B::fooA(int)const ? "
        <<is_available(B,void(int),fooA) <<endl;
 
    cout<< "is available void B.fooA(int) ? "
        << is_available_method(B,void(int),fooA) <<endl;
 
    cout<< "is available void B.fooA(int)const ? "
        << is_available_cmethod(B,void(int),fooA) <<endl;
 
    cout<< "is available int B.fooB() ? "
        << is_available_method(B,int(),fooB) <<endl;
 
    cout<< "is available void B.private_foo() ? "      
        << is_available(B,void(),private_foo) <<endl;
}




Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)