Я люблю сопоставление с образцом стиля Haskell.
У меня есть свой код C++ следующим образом:
ObjectPtr ptr;
if(ptr.isType<Foo>()) { // isType returns a bool
Ptr<Foo> p = ptr.convertAs<Foo>(); // convertAs returns a Ptr<Foo>
......
}
if(ptr.isType<Bar>()) {
Ptr<Bar> p = ptr.convertAs<Bar>();
......
}
Теперь, есть ли какие-либо макросы, которые я могу сделать, определяют для упрощения этого? Я обдумывал это некоторое время, но не могу упростить его далее.
Спасибо!
Закрытия в JDK7 на данный момент коротки по деталям. В презентации на Devoxx использованные примеры были очень похожи на предложение по закрытию FCM .
Предполагая, что спецификация используется в JDK7, тогда я думаю, что ответ на части 2, 3 и 4 вашего вопроса да (хотя я вполне могу быть неправильным).
Для части 1 - я думаю, что должно быть возможно иметь массивы, поскольку литералы методов могут назначаться объектам Method.
Для части 5 я бы предположил, что исполнение будет похоже на внутренние классы.
Извините, что я немного расплывчата - надеюсь, это немного поможет. Вероятно, еще рано ответить на ваши вопросы с уверенностью.
-121--2986093- Я предполагаю, что шаблон Ptr
имеет понятие нулевого указателя.
ObjectPtr ptr;
if(Ptr<Foo> p = ptr.convertAs<Foo>()) { // convertAs returns a NULL pointer if the conversion can't be done.
......
}
if(Ptr<Bar> p = ptr.convertAs<Bar>()) {
......
}
Хотя, как отметили другие, включение типа обычно является признаком того, что вы делаете что-то неправильно в C++. Вместо этого следует использовать виртуальные функции.
dynamic_cast
будет делать то, что вы хотите
struct A {
virtual ~A() {}
};
struct B : struct A { ... };
struct C : struct A { ... };
A * a = new C;
if ( C * c = dynamic_cast<C*>( a ) ) {
c->someCfunc();
}
else if ( B * b = dynamic_cast<B*>( a ) ) {
b->someBfunc();
}
else {
throw "Don't know that type";
}
Мне нравится совпадение по шаблону в стиле Хаскелла.
Тогда напишите свою программу в Haskell.
Вы пытаетесь переключить тип. Это обычная вещь, которую люди делают, если хотят избежать виртуальных функций. Последние являются краеугольным камнем того, что такое OO в C++. Если Вы хотите их избежать, зачем Вы программируете на Си++?
Что касается того, почему это не одобряется: Представьте, что у вас так много кода
if(ptr.isType<Foo>()) ...
if(ptr.isType<Bar>()) ...
размазанного по всему коду, а потом кто-то приходит и добавляет Baz
к возможным типам, которые могут представлять ptr
. Теперь вы охотитесь по большой базе кода, пытаетесь найти все те места, где вы переключили тип, и пытаетесь выяснить, в какие из них нужно добавить Baz
.
И, как у Мерфи, как раз когда вы закончили, появляется Фоз
, который тоже нужно добавить как тип. (Или, подумав еще раз, если у Мерфи есть свой путь, он прокрадывается в до , то у вас был шанс добавить слишком полный Baz
.).
Думаю, этот макрос делает именно то, что вы хотите:
#define DYN_IF(dest_type, dest_ptr, src_ptr) \
if((src_ptr).isType<dest_type>()) \
if(int dest_type##dest_ptr = 1) \
for(Ptr<dest_type> dest_ptr = (src_ptr).convertAs<dest_type>(); \
dest_type##dest_ptr; \
dest_type##dest_ptr=0)
Использование:
ObjectPtr ptr;
DYN_IF(Foo, foo_ptr, ptr) {
// foo_ptr is Ptr<Foo>
}
DYN_IF(Bar, bar_ptr, ptr) // Works without braces too for single statement
// bar_ptr is Ptr<Bar>
Я бы не рекомендовал такие вещи в коде, который предназначен быть прочитанным кем-то другим, но поскольку вы упомянули слово «макрос» ...
Кроме того, я бы не стал притворяться, что это имеет какое-либо отношение к сопоставлению с образцом в стиле Haskell / OCaml. Отметьте Scala, если вам нужен язык с семантикой, подобной C ++ (ну, вроде как), и истинным сопоставлением с образцом.
Попытка смоделировать стиль совмещения паттернов в C++ с помощью RTTI - это аккуратная идея, но у нее обязательно есть недостатки, так как есть некоторые существенные различия между конструкторами типов типов Haskell и Standard ML и подклассами C++. (Примечание: ниже я использую стандартный синтаксис ML, потому что он мне больше нравится)
a::b::c::ds
связывает первые три элемента списка с a
, b
, и c
, а остальные элементы списка с ds
). В C++ вам все равно придется копаться в реальных вложенных структурах, если только вы или кто-то другой не предложит гораздо более сложные макросы, чем те, которые были предложены здесь. 'a option = NONE | SOME из 'a
определяет один новый тип: 'a option
. Конструкторы NONE
и SOME
не являются типами, это значения с типами 'a опции
и 'a -> 'опции
, соответственно. В C++, когда вы определяете подклассы типа Foo
и Bar
для моделирования конструкторов типов, вы получаете новые типы. SOME
являются первоклассными функциями, которые строят значения того типа данных, к которому они принадлежат. Например, map SOME
имеет тип 'a list -> 'список опций'
. В Си++, используя подклассы для моделирования конструкторов типов, вы не получаете этой возможности. В конце концов, получаете ли вы достаточную выгоду от симулированного совпадения по шаблону по сравнению с более типичным использованием полиморфизма на Си++? Стоит ли использовать макросы, чтобы сделать симулированное совпадение паттернов немного более кратким (в то время как запутывая его для всех остальных, кто читает ваш код)?