Delphi vs C++ vs C#
, ну и Java немножко, где-то ближе к старшему байту номеров страниц
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
| [216.73.216.156] |
|
|
Правила раздела:
| Страницы: (495) « Первая ... 353 354 [355] 356 357 ... 494 495 ( Перейти к последнему сообщению ) |
Delphi vs C++ vs C#
, ну и Java немножко, где-то ближе к старшему байту номеров страниц
|
Сообщ.
#5311
,
|
|
|
|
Цитата korvin @ А почему integer сразу не может быть экземпляром? Или почему компилятор сам не вставляет экземпляр? думаю - это вопрос к микрософту. Скорее всего потому что это усложнило бы компилятор. но при это не дало бы особых бенефитов. |
|
Сообщ.
#5312
,
|
|
|
|
Цитата jack128 @ Компилятор может быть немного и усложнился бы (хотя и незаметно по сравнению с уже имеющейся сложностью), но Скорее всего потому что это усложнило бы компилятор. но при это не дало бы особых бенефитов. ![]() ![]() if typeof(object) == typeof(SomeType) then ![]() ![]() if typeof(object) == SomeType then Так же как ![]() ![]() write(SomeType.name) ![]() ![]() write(typeof(SomeType)) ![]() ![]() write(SomeType) |
|
Сообщ.
#5313
,
|
|
|
|
Цитата amk @ write(typeof(SomeType)) , тем более, если судить по словам Romkin'а, последнее означает то же самое, что и write(SomeType) Прошу не путаться, а посмотреть пример. Там writeln(typeof(T)), что совсем не то же самое что writeln(typeof(integer)). Добавлено Цитата amk @ if typeof(object) == typeof(SomeType) then читается хуже, чем if typeof(object) == SomeType then А как раз второе и применяется Добавлено Цитата amk @ write(SomeType.name) понятнее, чем write(typeof(SomeType)) Третье: в первом варианте тебе необходимо, чтобы любой тип в системе имел атрибут "name". Что скорее всего подразумевает наличие одного общего предка. Второй вариант этого не требует. |
|
Сообщ.
#5314
,
|
|
|
|
Цитата Romkin @ Там writeln(typeof(T)), что совсем не то же самое что writeln(typeof(integer)). Во всех языках программирования переменная везде может быть заменена на ее значение (иногда правда это значение приходится заключать в скобки). У тебя T - переменная, уже имеющая своим значением некий тип (может быть и integer). То есть оба приведенных в цитате выражения должны иметь одинаковую семантику. И если второе бессмысленно, то и первое смысла не имеет. Цитата Romkin @ Применяется как раз typeof(SomeType). Поскольку T описывает тип, а не значение.А как раз второе и применяется Цитата Romkin @ Никоим образом, я не собираюсь у объектов спрашивать, как зовут их тип. У объектов я спрошу каков их тип (например посредством вызова притворяющегося функцией оператора typeof). А уже у типа буду спрашивать, как его зовут. Так что достаточно, чтобы один единственный тип (метатип), значениями которого и являются описатели типов, имел атрибут name (он может иметь еще кучу других полезных атрибутов). Это будет аналог RTTI. тебе необходимо, чтобы любой тип в системе имел атрибут "name" |
|
Сообщ.
#5315
,
|
|
|
|
Цитата amk @ тебе необходимо, чтобы любой тип в системе имел атрибут "name" Никоим образом, я не собираюсь у объектов спрашивать, как зовут их тип. У объектов я спрошу каков их тип (например посредством вызова притворяющегося функцией оператора typeof). А уже у типа буду спрашивать, как его зовут. Так что достаточно, чтобы один единственный тип (метатип), значениями которого и являются описатели типов, имел атрибут name (он может иметь еще кучу других полезных атрибутов). Это будет аналог RTTI. Об этом я и говорю: общий предок для всех типов. Или некий метатип. Это не RTTI. |
|
Сообщ.
#5316
,
|
|
|
|
Цитата Romkin @ Это не RTTI. почему? |
|
Сообщ.
#5317
,
|
|
|
|
Цитата Romkin @ То есть из-за того, что в Delphi общий предок - TObject там тоже не RTTI? Об этом я и говорю: общий предок для всех типов. Или некий метатип. Это не RTTI. |
|
Сообщ.
#5318
,
|
|
|
|
Yes! Готова (кажется) многопараметровость и их несимметричность. Протестировано на трёхпараметрическом мультиметоде с иерархией среднего параметра, отличной от иерархий крайних.
Добавлено Типа ![]() ![]() apply(Base* b1, Other* o, Base* b2) |
|
Сообщ.
#5319
,
|
|
|
|
Вот, покоментил малость.
Очень много кода ![]() ![]() /*******************************************************\ ** Списки типов, заменяющие variadic templates в C++0x ** \*******************************************************/ /* Терминальный тип */ struct NullType {}; /* Список типов. L - голова, любой тип, кроме терминального и списка. R - хвост, либо терминальный тип, либо список */ template <typename L, typename R> struct TList { typedef L Head; typedef R Tail; }; /* Генератор веерной иерархии на основе списка типов T. Все типы из списка T применяются к шаблону Node. Первый его параметр - параметризированный тип из списка, второй - тип возвращаемого значения мультиметода. Все получившиеся Node<T::Head> не состоят в родстве относительно друг друга, что обеспечивает их равноправность при перекрытии. Получившая веерная иерархия будет т.о. содержать в каждом луче веера декларацию интерфейса абстрактного акцептора для отдельного типа из списка. От базы (самого производного класса GenHierarchy<>) можно однозначно добраться до любого узла путём обычного восходящего приведения типов. */ template <template <typename, typename> class Node, typename Ret, typename T>struct GenHierarchy; template <template <typename, typename> class Node, typename Ret, typename L, typename R> struct GenHierarchy<Node, Ret, TList<L, R> >: public Node<L, Ret>, public GenHierarchy<Node, Ret, R> { }; template <template <typename, typename> class Node, typename Ret> struct GenHierarchy<Node, Ret, NullType> { }; /* Метафункция получения последнего элемента списка */ template <typename TL> struct Last; template <typename L, typename R> struct Last<TList<L, R > > { typedef typename Last<R>::result result; }; template <typename T> struct Last<TList<T, NullType> > { typedef T result; }; /* Метафункция получения длины списка */ template <typename TL> struct Length; template <typename L, typename R> struct Length<TList<L, R> > { enum { value = Length<R>::value + 1 }; }; template <> struct Length<NullType> { enum { value = 0 }; }; /**********************************************************\ ** Кортежи. В C++03 в STL их нет, а BOOSTовые не подходят ** ** ввиду иной архитектуры ** \**********************************************************/ /* Узел кортежа, одно поле. Первый параметр требуется для уникальной его идентификации, если в пределах кортежа T неуникален. */ template <typename Hash, typename T> struct Field { T data; Field(const T& t) : data(t){} }; /* Генератор кортежа на основе списка типов T. В качестве Hash используется текущий срез списка типов. */ template <typename T> struct Tuple; template <typename L, typename R> struct Tuple<TList<L, R> >: public Field<TList<L, R>, L>, public Tuple<R> { typedef TList<L, R> TypeList; typedef Field<TList<L, R>, L> FieldType; typedef L DataType; typedef Tuple<R> base_type; /* Конструкторы нужны, чтобы позволить полям иметь константные и ссылочные типы. */ /* Добавление нового поля в начало кортежа. */ Tuple(L t, const base_type& tpl): Field<TList<L, R>, L>(t), base_type(tpl) {} /* Создание кортежа разным количеством параметров. Без копипаста в C++03 никак, увы. */ Tuple(L t0): Field<TList<L, R>, L>(t0) {} template <typename T1> Tuple(L t0, T1 t1): Field<TList<L, R>, L>(t0), base_type(t1) {} template <typename T1, typename T2> Tuple(L t0, T1 t1, T2 t2): Field<TList<L, R>, L>(t0), base_type(t1, t2) {} template <typename T1, typename T2, typename T3> Tuple(L t0, T1 t1, T2 t2, T3 t3): Field<TList<L, R>, L>(t0), base_type(t1, t2, t3) {} template <typename T1, typename T2, typename T3, typename T4> Tuple(L t0, T1 t1, T2 t2, T3 t3, T4 t4): Field<TList<L, R>, L>(t0), base_type(t1, t2, t3, t4) {} template <typename T1, typename T2, typename T3, typename T4, typename T5> Tuple(L t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5): Field<TList<L, R>, L>(t0), base_type(t1, t2, t3, t4, t5) {} template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> Tuple(L t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6): Field<TList<L, R>, L>(t0), base_type(t1, t2, t3, t4, t5, t6) {} template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> Tuple(L t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7): Field<TList<L, R>, L>(t0), base_type(t1, t2, t3, t4, t5, t6, t7) {} template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> 01 Tuple(L t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8): Field<TList<L, R>, L>(t0), base_type(t1, t2, t3, t4, t5, t6, t7, t8) {} template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9> Tuple(L t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9): Field<TList<L, R>, L>(t0), base_type(t1, t2, t3, t4, t5, t6, t7, t8, t9) {} }; template <> struct Tuple<NullType> { }; /* Получить срез кортежа Tpl по номеру поля I от начала */ template <int I, typename Tpl> struct GetTupleSlice { typedef typename GetTupleSlice<I-1, typename Tpl::base_type>::result result; }; template <typename Tpl> struct GetTupleSlice<0, Tpl> { typedef Tpl result; }; /* Получить поле I кортежа Tpl */ template <int I, typename Tpl> typename GetTupleSlice<I, Tpl>::result::DataType& GetField(Tpl& tuple) { typedef typename GetTupleSlice<I, Tpl>::result TupleSlice; return static_cast<Field<typename TupleSlice::TypeList, typename TupleSlice::DataType>&>(tuple).data; } /********************************************************************************\ ***************** Далее следует реализация мультиметодов **************** \********************************************************************************/ /* Узел веерной иерархии абстрактных акцепторов */ template <typename T, typename Ret> class AcceptorBase { public: virtual Ret Accept(T* obj) = 0; }; /* Генератор веерной иерархии абстрактных акцепторов. Первый параметр - исходный список, второй - тип возвращаемого значения мультиметода */ template <typename TL, typename Ret> class Acceptor: public GenHierarchy<AcceptorBase, Ret, TL> { public: typedef TL TypeList; /* Генератор селекторов - конкретных акцепторов, реализующих чистые методы абстракных акцепторов. */ template <typename T, template <typename, typename, typename, typename, typename> class GA, typename ATL, typename CTL, typename TPL> struct MakeAcceptor { typedef GA<T, TL, ATL, CTL, TPL> type; }; }; /********************************************************************************\ ***************** Абстрактный диспетчер **************** \********************************************************************************/ template <typename T> struct OUTPUT { template <typename X> struct DoIt {}; DoIt<T> dummy; }; template <typename, typename> class CallDispatcher; /* Первый параметр - конкретный диспетчер, второй - список типов конкретных акцепторов для каждого параметра мультиметода, третий - тип возвращаемого мультиметодом значения. */ template <typename DI, typename TTl, typename ret_type = void> struct Dispatcher { /* Селекторы первого, всех промежуточних и последнего параметров мультиметода соответственно. */ template <typename T, typename ATL, typename CTL, typename PTL, typename TPL> struct FirstAcceptorCaller; template <typename T, typename ATL, typename CTL, typename PTL, typename TPL> struct InterAcceptorCaller; template <typename T, typename ATL, typename CTL, typename PTL, typename TPL> struct LastAcceptorCaller; /* Генератор очередного селектора на основе очередного среза списка типов конкретных акцепторов. */ template <typename T, typename ATL, typename PTL, typename TPL> struct AcceptorMaker; // эти две специализации требуются operator(), которые ещё только получают "самые базовые типы" template <typename T, typename AL, typename AR> struct AcceptorMaker<T, TList<AL, AR>, NullType, NullType> { typedef typename Last<typename AL::TypeList>::result most_base; }; /* template <typename T, typename AL> struct AcceptorMaker<T, TList<AL, NullType>, NullType, NullType> { typedef typename Last<typename AL::TypeList>::result most_base; };*/ // эта специализация запускает цикл восстановаления динамических типов параметров template <typename T, typename AL, typename AR, typename TPL> struct AcceptorMaker<T, TList<AL, AR>, NullType, TPL> { typedef typename AL::template MakeAcceptor<T, FirstAcceptorCaller, TList<AL, AR>, NullType, TPL>::type acceptor_type; typedef typename Last<typename AL::TypeList>::result most_base; }; // эта специализация является очередной итерацией цикла и восстанавливает очередной тип template <typename T, typename AL, typename AR, typename PTL, typename TPL> struct AcceptorMaker<T, TList<AL, AR>, PTL, TPL> { typedef typename AL::template MakeAcceptor<T, InterAcceptorCaller, TList<AL, AR>, PTL, TPL>::type acceptor_type; typedef typename Last<typename AL::TypeList>::result most_base; }; // эти две специализации является последней итерацией цикла; // первая вызывается InterAcceptorCaller, вторая FirstAcceptorCaller template <typename T, typename AL, typename PTL, typename TPL> struct AcceptorMaker<T, TList<AL, NullType>, PTL, TPL> { typedef typename AL::template MakeAcceptor<T, LastAcceptorCaller, TList<AL, NullType>, PTL, TPL>::type acceptor_type; typedef typename Last<typename AL::TypeList>::result most_base; }; template <typename T, typename AL, typename TPL> struct AcceptorMaker<T, TList<AL, NullType>, NullType, TPL> { typedef typename AL::template MakeAcceptor<T, LastAcceptorCaller, TList<AL, NullType>, NullType, TPL>::type acceptor_type; typedef typename Last<typename AL::TypeList>::result most_base; }; /* Реализация селекторов. Общий принцип заключается в генерации линейной иерархии на основе конкретного акцептора. Очередной узел в иерархии является производным от предыдущего узла и реализует чистый метод очередного абстрактного акцептора из веерной иерархии. Последний узел производится непосредственно от акцептора. В целом, т.к. они строятся на основе одинаковых списков типов, реализованным оказывается каждый, и каждый - в своём узле линейной иерархии. В результате позднее связываение метода Accept() вызовет нужный узел, которому известен его тип в списке, тем самым динамический тип восстанавливается, тип параметра приводится к восстановленному, оба накапливаются в списке восстановленных типов и в кортеже их значений соответственно, и в заключение вызывается следующий селектор. Параметры: - тип возвращаемого значения; - срез списка типов иерархии своего параметра; - срез списка типов абстракных акцепторов; - список восстановленных динамических типов предыдущих параметров; - срез списка "базовых" типов параметров мультиметода. */ /* Реализация селектора последнего параметра мультиметода. Особенности: - срез списка "базовых" типов параметров мультиметода не используется, ибо тут он уже пуст. - вызывает конкретный диспетчер вместо следующего селектора. */ template <typename L, typename R, typename CTL, typename PTL, typename TPL> struct LastAcceptorCaller<ret_type, TList<L, R>, CTL, PTL, TPL> : public LastAcceptorCaller<ret_type, R, CTL, PTL, TPL> { typedef LastAcceptorCaller<ret_type, TList<L, R>, CTL, PTL, TPL> this_type; typedef LastAcceptorCaller<ret_type, R, CTL, PTL, TPL> base_type; typedef typename Last<R>::result most_base_type; LastAcceptorCaller(Tuple<PTL>& dst, TPL& src) : base_type(dst, src) {} /* Восстанавливает тип последнего параметра и вызывает нужную специализацию конкретного диспеитчера, в зависимости от длины списка параметров мультиметода. */ ret_type Accept(L* obj) { return CallDispatcher<DI, ret_type>::template apply<TList<L*, PTL>, Length<PTL>::value>::call(base_type::m_Params, obj); } }; template <typename L, typename CTL, typename PTL, typename TPL> struct LastAcceptorCaller<ret_type, TList<L, NullType>, CTL, PTL, TPL> : public CTL::Head { typedef LastAcceptorCaller<ret_type, TList<L, NullType>, CTL, PTL, TPL> this_type; LastAcceptorCaller(Tuple<PTL>& dst, TPL&) : m_Params(dst) {} ret_type Accept(L* obj) { return CallDispatcher<DI, ret_type>::template apply<TList<L*, PTL>, Length<PTL>::value>::call(m_Params, obj); } Tuple<PTL> &m_Params; }; /* Реализация селектора промежуточного параметра мультиметода. Особенности: - не используется, если мультиметод имеет только 2 параметра. */ template <typename L, typename R, typename CTL, typename PTL, typename TPL> struct InterAcceptorCaller<ret_type, TList<L, R>, CTL, PTL, TPL> : public InterAcceptorCaller<ret_type, R, CTL, PTL, TPL> { typedef InterAcceptorCaller<ret_type, TList<L, R>, CTL, PTL, TPL> this_type; typedef InterAcceptorCaller<ret_type, R, CTL, PTL, TPL> base_type; typedef typename base_type::most_base_type most_base_type; InterAcceptorCaller(Tuple<PTL>& dst, TPL& src): base_type(dst, src) {} /* Восстанавливает тип очередного параметра, генерирует следующий селектор, передавая ему следующий срез списка акцепторов и "базовых" типов параметров и накопленную восстановленную информацию и вызывает его. */ ret_type Accept(L* obj) { typedef typename AcceptorMaker<ret_type, typename CTL::Tail, TList<L*, PTL>, typename TPL::base_type>::acceptor_type acceptor; Tuple<TList<L*, PTL> > dstParams(obj, base_type::m_Params); acceptor a(dstParams, static_cast<typename TPL::base_type&>(base_type::m_Args)); return GetField<0>(base_type::m_Args)->Accept(a); } }; template <typename L, typename CTL, typename PTL, typename TPL> struct InterAcceptorCaller<ret_type, TList<L, NullType>, CTL, PTL, TPL> : public CTL::Head { typedef InterAcceptorCaller<ret_type, TList<L, NullType>, CTL, PTL, TPL> this_type; typedef typename Last<typename CTL::Head::TypeList>::result most_base_type; InterAcceptorCaller(Tuple<PTL>& dst, TPL& src): m_Params(dst), m_Args(src) {} ret_type Accept(L* obj) { typedef typename AcceptorMaker<ret_type, typename CTL::Tail, TList<L*, PTL>, typename TPL::base_type>::acceptor_type acceptor; Tuple<TList<L*, PTL> > dstParams(obj, m_Params); acceptor a(dstParams, static_cast<typename TPL::base_type&>(m_Args)); return GetField<0>(m_Args)->Accept(a); } Tuple<PTL> m_Params; TPL &m_Args; }; /* Реализация селектора первого параметра мультиметода. Особенности: - список восстановленных типов и кортеж их значений отсутствует. */ template <typename L, typename R, typename CTL, typename PTL, typename TPL> struct FirstAcceptorCaller<ret_type, TList<L, R>, CTL, PTL, TPL> : public FirstAcceptorCaller<ret_type, R, CTL, PTL, TPL> { typedef FirstAcceptorCaller<ret_type, R, CTL, PTL, TPL> base_type; typedef typename base_type::most_base_type most_base_type; FirstAcceptorCaller(TPL& tpl): base_type(tpl) {} /* Восстанавливает тип первого параметра, генерирует следующий селектор, передавая ему следующий срез списка акцепторов и "базовых" типов параметров и создавая для него первичные список восстановленных типов из одного элемента и кортеж с его значением, и вызывает его. */ ret_type Accept(L* obj) { typedef typename AcceptorMaker<ret_type, typename CTL::Tail, TList<L*, PTL>, typename TPL::base_type>::acceptor_type acceptor; Tuple<TList<L*, NullType> > dstParams(obj); acceptor a(dstParams, static_cast<typename TPL::base_type&>(base_type::m_Args)); return GetField<0>(base_type::m_Args)->Accept(a); } }; template <typename L, typename CTL, typename PTL, typename TPL> struct FirstAcceptorCaller<ret_type, TList<L, NullType>, CTL, PTL, TPL> : public CTL::Head { typedef typename Last<typename CTL::Head::TypeList>::result most_base_type; FirstAcceptorCaller(TPL& tpl): m_Args(tpl) {} ret_type Accept(L* obj) { typedef typename AcceptorMaker<ret_type, typename CTL::Tail, TList<L*, PTL>, typename TPL::base_type>::acceptor_type acceptor; Tuple<TList<L*, NullType> > dstParams(obj); acceptor a(dstParams, static_cast<typename TPL::base_type&>(m_Args)); return GetField<0>(m_Args)->Accept(a); } TPL &m_Args; }; /* Обобщённая точка входа. Создаёт селектор первого параметра и вызывает его. */ template <typename Tpl> static ret_type doIt(Tpl& tpl) { typedef typename Tpl::base_type TupleType; typedef typename AcceptorMaker<ret_type, TTl, NullType, TupleType>::acceptor_type acceptor; TupleType& srcParams(static_cast<TupleType&>(tpl)); acceptor a(srcParams); return GetField<0>(tpl)->Accept(a); } /* Да, тут много копипаста. Раздельные точки входа для мультиметодов с разным количеством параметров. Обобщённая точка входа в C++03 тут невозможна. По этой же причине конкретные "базовые" типы, которые уже сейчас можно получить из списка акцепторов, тут привести невозможно, если operator() будет нешаблонным, т.к. в этом случае, инстанцируя прототип, компилятор будет ругаться ошибками на TTl::Tail:: ... Tail::Head::TypeList, чьи длины превышают количество параметров мультиметода. Проблема решается переносом таких сигнатур вовнутрь шаблонных реализаций operator(). Вариант со SFINAE сложнее, ИМХО. Создаёт кортеж "базовых" типов параметров, заполняет его, генерирует селектор первого параметра и вызывает его с этм кортежем. */ template <typename T0, typename T1> ret_type operator ()(T0* p0, T1* p1) { typedef Tuple<TList<typename Last<typename TTl:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Head::TypeList>::result*, NullType> > > TupleType; TupleType tuple(p0, p1); return doIt(tuple); } template <typename T0, typename T1, typename T2> ret_type operator ()(T0* p0, T1* p1, T2* p2) { typedef Tuple<TList<typename Last<typename TTl:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Head::TypeList>::result*, NullType> > > > TupleType; TupleType tuple(p0, p1, p2); return doIt(tuple); } template <typename T0, typename T1, typename T2, typename T3> ret_type operator ()(T0* p0, T1* p1, T2* p2, T3* p3) { typedef Tuple<TList<typename Last<typename TTl:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Head::TypeList>::result*, NullType> > > > > TupleType; TupleType tuple(p0, p1, p2, p3); return doIt(tuple); } template <typename T0, typename T1, typename T2, typename T3, typename T4> ret_type operator ()(T0* p0, T1* p1, T2* p2, T3* p3, T4* p4) { typedef Tuple<TList<typename Last<typename TTl:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail::Head::TypeList>::result*, NullType> > > > > > TupleType; TupleType tuple(p0, p1, p2, p3, p4); return doIt(tuple); } template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5> ret_type operator ()(T0* p0, T1* p1, T2* p2, T3* p3, T4* p4, T5* p5) { typedef Tuple<TList<typename Last<typename TTl:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail::Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail:: Tail::Head::TypeList>::result*, NullType> > > > > > > TupleType; TupleType tuple(p0, p1, p2, p3, p4, p5); return doIt(tuple); } template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> ret_type operator ()(T0* p0, T1* p1, T2* p2, T3* p3, T4* p4, T5* p5, T6* p6) { typedef Tuple<TList<typename Last<typename TTl:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail::Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail:: Tail::Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail:: Tail::Tail::Head::TypeList>::result*, NullType> > > > > > > > TupleType; TupleType tuple(p0, p1, p2, p3, p4, p5, p6); return doIt(tuple); } template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7> ret_type operator ()(T0* p0, T1* p1, T2* p2, T3* p3, T4* p4, T5* p5, T6* p6, T7* p7) { typedef Tuple<TList<typename Last<typename TTl:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail::Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail:: Tail::Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail:: Tail::Tail::Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail:: Tail::Tail::Tail::Head::TypeList>::result*, NullType> > > > > > > > > TupleType; TupleType tuple(p0, p1, p2, p3, p4, p5, p6, p7); return doIt(tuple); } template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> ret_type operator ()(T0* p0, T1* p1, T2* p2, T3* p3, T4* p4, T5* p5, T6* p6, T7* p7, T8* p8) { typedef Tuple<TList<typename Last<typename TTl:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail::Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail:: Tail::Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail:: Tail::Tail::Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail:: Tail::Tail::Tail::Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail:: Tail::Tail::Tail::Tail::Head::TypeList>::result*, NullType> > > > > > > > > > TupleType; TupleType tuple(p0, p1, p2, p3, p4, p5, p6, p7, p8); return doIt(tuple); } template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9> ret_type operator ()(T0* p0, T1* p1, T2* p2, T3* p3, T4* p4, T5* p5, T6* p6, T7* p7, T8* p8, T9* p9) { typedef Tuple<TList<typename Last<typename TTl:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail:: Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail::Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail:: Tail::Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail:: Tail::Tail::Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail:: Tail::Tail::Tail::Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail:: Tail::Tail::Tail::Tail::Head::TypeList>::result*, TList<typename Last<typename TTl::Tail::Tail::Tail::Tail:: Tail::Tail::Tail::Tail::Tail::Head::TypeList>::result*, NullType> > > > > > > > > > > TupleType; TupleType tuple(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); return doIt(tuple); } }; /*******************************************************************************\ ***************** Конкретный диспетчер **************** \*******************************************************************************/ /* Первый параметр - пользовательский класс с реализациями перекрытых мультиметодов, второй - тип возвращаемого мультиметодом значения. */ template <typename UI, typename T> struct CallDispatcher { typedef T ret_type; /* И тут много копипаста. По той же причине. Вызывается последним селектором абстрактного диспетчера. Переводит кортеж значений восстановленных типов в последовательность параметров мультиметода. Ввиду того, что все типы восстановлены, тут задействуется обычная перегрузка, в процессе которой компилятор пробует вызвать один из подходящих перекрытий, базируясь главным образом на возможности неявного каста указателей на производные классы к указателям на базовые. Этим гарантируется одинаковые принципы отбора наиболее подходящего метода как для статического (раннего), так и для динамического (позднего) связывания. */ template <typename PL, int N> struct apply; template <typename PL> struct apply<PL, 1> { static T call(Tuple<typename PL::Tail>& pl, typename PL::Head& data) { return UI::apply(GetField<0>(pl), data); } }; template <typename PL> struct apply<PL, 2> { static T call(Tuple<typename PL::Tail>& pl, typename PL::Head& data) { return UI::apply(GetField<1>(pl), GetField<0>(pl), data); } }; template <typename PL> struct apply<PL, 3> { static T call(Tuple<typename PL::Tail>& pl, typename PL::Head& data) { return UI::apply(GetField<2>(pl), GetField<1>(pl), GetField<0>(pl), data); } }; template <typename PL> struct apply<PL, 4> { static T call(Tuple<typename PL::Tail>& pl, typename PL::Head& data) { return UI::apply(GetField<3>(pl), GetField<2>(pl), GetField<1>(pl), GetField<0>(pl), data); } }; template <typename PL> struct apply<PL, 5> { static T call(Tuple<typename PL::Tail>& pl, typename PL::Head& data) { return UI::apply(GetField<4>(pl), GetField<3>(pl), GetField<2>(pl), GetField<1>(pl), GetField<0>(pl), data); } }; template <typename PL> struct apply<PL, 6> { static T call(Tuple<typename PL::Tail>& pl, typename PL::Head& data) { return UI::apply(GetField<5>(pl), GetField<4>(pl), GetField<3>(pl), GetField<2>(pl), GetField<1>(pl), GetField<0>(pl), data); } }; template <typename PL> struct apply<PL, 7> { static T call(Tuple<typename PL::Tail>& pl, typename PL::Head& data) { return UI::apply(GetField<6>(pl), GetField<5>(pl), GetField<4>(pl), GetField<3>(pl), GetField<2>(pl), GetField<1>(pl), GetField<0>(pl), data); } }; template <typename PL> struct apply<PL, 8> { static T call(Tuple<typename PL::Tail>& pl, typename PL::Head& data) { return UI::apply(GetField<7>(pl), GetField<6>(pl), GetField<5>(pl), GetField<4>(pl), GetField<3>(pl), GetField<2>(pl), GetField<1>(pl), GetField<0>(pl), data); } }; template <typename PL> struct apply<PL, 9> { static T call(Tuple<typename PL::Tail>& pl, typename PL::Head& data) { return UI::apply(GetField<8>(pl), GetField<7>(pl), GetField<6>(pl), GetField<5>(pl), GetField<4>(pl), GetField<3>(pl), GetField<2>(pl), GetField<1>(pl), GetField<0>(pl), data); } }; }; ![]() ![]() // Две разные иерархии class Base; class D1; class D2; class D3; class Other; class O1; class O2; class O3; class O4; /* Самый базовый класс должен быть последним. Впрочем, заглянув к Александреску на книжку чаю, поиск самого базового из предоставленных можно автоматизировать. Я не стал копить сюда лишнего метакода, его и так выше крыши. */ typedef TList<D3, TList<D2, TList<D1, TList<Base, NullType> > > > Hierarchy; typedef TList<O3, TList<O2, TList<O1, TList<O4, TList<Other, NullType> > > > > OtherHierarchy; /* Создаём акцепторы по иерархиям */ typedef Acceptor<Hierarchy, void> ConcreteAcceptor; typedef Acceptor<OtherHierarchy, void> OtherConcreteAcceptor; /* Создаём списки акцепторов в соответствии с порядком параметров в мультиметодах */ typedef TList<ConcreteAcceptor, TList<ConcreteAcceptor, NullType> > Acceptors; typedef TList<ConcreteAcceptor, TList<OtherConcreteAcceptor, TList<ConcreteAcceptor, NullType> > > OtherAcceptors; /* Объявляем свои мультиметоды */ struct TestDispatch2; struct TestDispatch3; Dispatcher<TestDispatch2, Acceptors> disp1; // диспетчер первого мультиметода, с двумя параметрами Base* Dispatcher<TestDispatch3, OtherAcceptors> disp2; // диспетчер второго мультиметода, с тремя параметрами Base*, Other* и Base* Ниже тест. Ещё много кода ![]() ![]() /* Макро для удобства */ #define MAKE_ACCEPTABLE(A, C) virtual void Accept(A& a) \ { \ return static_cast<AcceptorBase<C, void>*>(&a)->Accept(this); \ } class Base { public: MAKE_ACCEPTABLE(ConcreteAcceptor, Base); }; class D1 : public Base { public: MAKE_ACCEPTABLE(ConcreteAcceptor, D1); }; class D2 : public D1 { public: MAKE_ACCEPTABLE(ConcreteAcceptor, D2); }; class D3 : public Base { public: MAKE_ACCEPTABLE(ConcreteAcceptor, D3); }; class Other { public: MAKE_ACCEPTABLE(OtherConcreteAcceptor, Other); }; class O1 : public Other { public: MAKE_ACCEPTABLE(OtherConcreteAcceptor, O1); }; class O2 : public Other { public: MAKE_ACCEPTABLE(OtherConcreteAcceptor, O2); }; class O3 : public O1 { public: MAKE_ACCEPTABLE(OtherConcreteAcceptor, O3); }; class O4 : public O2 { public: MAKE_ACCEPTABLE(OtherConcreteAcceptor, O4); }; /* Определяем несколько перекрытий для мультиметодов. Должны быть реализованы как перегруженные статические методы apply() в классе */ // двупараметрический мультиметод struct TestDispatch2 { static void apply(Base* b1, Base* b2) { std::cout << "Double Base-Base Dispatch" << std::endl; } static void apply(D1* o1, Base* o2) { std::cout << "Double D1-Base Dispatch" << std::endl; } static void apply(D1* o1, D2* o2) { std::cout << "Double D1-D2 Dispatch" << std::endl; } static void apply(D2* o1, D3* o2) { std::cout << "Double D2-D3 Dispatch" << std::endl; } static void apply(D3* o1, D2* o2) { std::cout << "Double D3-D2 Dispatch" << std::endl; } static void apply(D3* o1, D3* o2) { std::cout << "Double D3-D3 Dispatch" << std::endl; } }; // трёхпараметрический мультиметод struct TestDispatch3 { static void apply(Base* b1, Other* o, Base* b2) { std::cout << "Triple Base-Other-Base Dispatch" << std::endl; } static void apply(D1* b1, Other* o, Base* b2) { std::cout << "Triple D1-Other-Base Dispatch" << std::endl; } static void apply(D1* b1, O2* o, D2* b2) { std::cout << "Triple D1-O2-D2 Dispatch" << std::endl; } static void apply(D2* b1, Other* o, D3* b2) { std::cout << "Triple D2-Other-D3 Dispatch" << std::endl; } static void apply(D3* b1, Other* o, D1* b2) { std::cout << "Triple D3-Other-D1 Dispatch" << std::endl; } static void apply(D3* b1, O1* o, D3* b2) { std::cout << "Triple D3-O1-D3 Dispatch" << std::endl; } static void apply(D3* b1, O3* o, D2* b2) { std::cout << "Triple D3-O3-D2 Dispatch" << std::endl; } static void apply(D3* b1, O4* o, D2* b2) { std::cout << "Triple D3-O4-D2 Dispatch" << std::endl; } }; int main() { Base b; D1 d1; D2 d2; D3 d3; Other o; O1 o1; O2 o2; O3 o3; O4 o4; { disp1(&b , &b ); disp1(&b , &d1); disp1(&b , &d2); disp1(&b , &d3); std::cout << std::endl; disp1(&d1, &b ); disp1(&d1, &d1); disp1(&d1, &d2); disp1(&d1, &d3); std::cout << std::endl; disp1(&d2, &b ); disp1(&d2, &d1); disp1(&d2, &d2); disp1(&d2, &d3); std::cout << std::endl; disp1(&d3, &b ); disp1(&d3, &d1); disp1(&d3, &d2); disp1(&d3, &d3); } std::cout << std::endl << std::endl; { disp2(&b , &o , &b ); disp2(&b , &o , &d1); disp2(&b , &o , &d2); disp2(&b , &o , &d3); std::cout << std::endl; disp2(&b , &o1, &b ); disp2(&b , &o1, &d1); disp2(&b , &o1, &d2); disp2(&b , &o1, &d3); std::cout << std::endl; disp2(&b , &o2, &b ); disp2(&b , &o2, &d1); disp2(&b , &o2, &d2); disp2(&b , &o2, &d3); std::cout << std::endl; disp2(&b , &o3, &b ); disp2(&b , &o3, &d1); disp2(&b , &o3, &d2); disp2(&b , &o3, &d3); std::cout << std::endl; disp2(&b , &o4, &b ); disp2(&b , &o4, &d1); disp2(&b , &o4, &d2); disp2(&b , &o4, &d3); std::cout << std::endl << std::endl; disp2(&d1, &o , &b ); disp2(&d1, &o , &d1); disp2(&d1, &o , &d2); disp2(&d1, &o , &d3); std::cout << std::endl; disp2(&d1, &o1, &b ); disp2(&d1, &o1, &d1); disp2(&d1, &o1, &d2); disp2(&d1, &o1, &d3); std::cout << std::endl; disp2(&d1, &o2, &b ); disp2(&d1, &o2, &d1); disp2(&d1, &o2, &d2); disp2(&d1, &o2, &d3); std::cout << std::endl; disp2(&d1, &o3, &b ); disp2(&d1, &o3, &d1); disp2(&d1, &o3, &d2); disp2(&d1, &o3, &d3); std::cout << std::endl; disp2(&d1, &o4, &b ); disp2(&d1, &o4, &d1); disp2(&d1, &o4, &d2); disp2(&d1, &o4, &d3); std::cout << std::endl << std::endl; disp2(&d2, &o , &b ); disp2(&d2, &o , &d1); disp2(&d2, &o , &d2); disp2(&d2, &o , &d3); std::cout << std::endl; disp2(&d2, &o1, &b ); disp2(&d2, &o1, &d1); disp2(&d2, &o1, &d2); disp2(&d2, &o1, &d3); std::cout << std::endl; disp2(&d2, &o2, &b ); disp2(&d2, &o2, &d1); disp2(&d2, &o2, &d2); disp2(&d2, &o2, &d3); std::cout << std::endl; disp2(&d2, &o3, &b ); disp2(&d2, &o3, &d1); disp2(&d2, &o3, &d2); disp2(&d2, &o3, &d3); std::cout << std::endl; disp2(&d2, &o4, &b ); disp2(&d2, &o4, &d1); disp2(&d2, &o4, &d2); disp2(&d2, &o4, &d3); std::cout << std::endl << std::endl; disp2(&d3, &o , &b ); disp2(&d3, &o , &d1); disp2(&d3, &o , &d2); disp2(&d3, &o , &d3); std::cout << std::endl; disp2(&d3, &o1, &b ); disp2(&d3, &o1, &d1); disp2(&d3, &o1, &d2); disp2(&d3, &o1, &d3); std::cout << std::endl; disp2(&d3, &o2, &b ); disp2(&d3, &o2, &d1); disp2(&d3, &o2, &d2); disp2(&d3, &o2, &d3); std::cout << std::endl; disp2(&d3, &o3, &b ); disp2(&d3, &o3, &d1); disp2(&d3, &o3, &d2); disp2(&d3, &o3, &d3); std::cout << std::endl; disp2(&d3, &o4, &b ); disp2(&d3, &o4, &d1); disp2(&d3, &o4, &d2); disp2(&d3, &o4, &d3); std::cout << std::endl << std::endl; } std::cout << std::endl; return 0; } |
|
Сообщ.
#5320
,
|
|
|
|
|
Сообщ.
#5321
,
|
|
|
|
>600 строк.
Firefox этим уже известен. IE тормозит секунд ~10. |
|
Сообщ.
#5322
,
|
|
|
|
Цитата Qraizer @ В принципе этим уже можно пользоваться. Выкладываю, чтоб было на что посмотреть, покритиковать и багорепортнуть. Но вообще это ещё не конец. Кто-нибудь возьмётся на вариадики переписать? Троекратное гип-гип github!, гип-гип github!, гип-гип github! Ложка дёгтя: мне категорически не нравится перечисление всех классов иерархий ![]() Chrome - шуршит и не чихает |
|
Сообщ.
#5323
,
|
|
|
|
Quraizer, эм... вроде ж ты же предлагал тут пример определения наследования в compile-time с поиощью шаблонов, может его прикрутить вместо ручного указания иерархии? при том, что фактически у тебя классы иерархии, как я понял, наследниками не являются?
|
|
Сообщ.
#5324
,
|
|
|
|
Угу. Мне тоже. С другой стороны это позволяет некоторые классы в иерархии не использовать как целевых кандидатов, просто не указав их в списке. Польза сомнительная, зато есть оправдание
В С++11 та же фигня. Добавлено Впрочем, у меня есть одна мысль, надо ею подумать. Вряд ли, но мало ли, вдруг чего надумается. |
|
Сообщ.
#5325
,
|
|
|
|
т.е. я к тому, что будет, если я вызову метод apply у которого определена реализация для (Base* obj) к переменной типа D1*? ведь по твоей иерархии D1 -- наследник Base, но сам класс D1 наследником Base не является
|