Стиль сопоставления с образцом в C++?

Я люблю сопоставление с образцом стиля 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>();
  ......
}

Теперь, есть ли какие-либо макросы, которые я могу сделать, определяют для упрощения этого? Я обдумывал это некоторое время, но не могу упростить его далее.

Спасибо!

7
задан anon 7 February 2010 в 10:29
поделиться

5 ответов

Закрытия в 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++. Вместо этого следует использовать виртуальные функции.

3
ответ дан 6 December 2019 в 06:24
поделиться

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";
}
7
ответ дан 6 December 2019 в 06:24
поделиться

Мне нравится совпадение по шаблону в стиле Хаскелла.

Тогда напишите свою программу в Haskell.

Вы пытаетесь переключить тип. Это обычная вещь, которую люди делают, если хотят избежать виртуальных функций. Последние являются краеугольным камнем того, что такое OO в C++. Если Вы хотите их избежать, зачем Вы программируете на Си++?


Что касается того, почему это не одобряется: Представьте, что у вас так много кода

if(ptr.isType<Foo>()) ...
if(ptr.isType<Bar>()) ... 

размазанного по всему коду, а потом кто-то приходит и добавляет Baz к возможным типам, которые могут представлять ptr. Теперь вы охотитесь по большой базе кода, пытаетесь найти все те места, где вы переключили тип, и пытаетесь выяснить, в какие из них нужно добавить Baz.

И, как у Мерфи, как раз когда вы закончили, появляется Фоз, который тоже нужно добавить как тип. (Или, подумав еще раз, если у Мерфи есть свой путь, он прокрадывается в до , то у вас был шанс добавить слишком полный Baz.).

7
ответ дан 6 December 2019 в 06:24
поделиться

Думаю, этот макрос делает именно то, что вы хотите:

#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 ++ (ну, вроде как), и истинным сопоставлением с образцом.

2
ответ дан 6 December 2019 в 06:24
поделиться

Попытка смоделировать стиль совмещения паттернов в C++ с помощью RTTI - это аккуратная идея, но у нее обязательно есть недостатки, так как есть некоторые существенные различия между конструкторами типов типов Haskell и Standard ML и подклассами C++. (Примечание: ниже я использую стандартный синтаксис ML, потому что он мне больше нравится)

  • В Haskell и Standard ML сравнение по шаблону может связывать вложенные значения с переменными по шаблону для вас (например шаблон a::b::c::ds связывает первые три элемента списка с a, b, и c, а остальные элементы списка с ds). В C++ вам все равно придется копаться в реальных вложенных структурах, если только вы или кто-то другой не предложит гораздо более сложные макросы, чем те, которые были предложены здесь.
  • В Haskell и Standard ML объявление типа конструктора типов данных типа 'a option = NONE | SOME из 'a определяет один новый тип: 'a option. Конструкторы NONE и SOME не являются типами, это значения с типами 'a опции и 'a -> 'опции, соответственно. В C++, когда вы определяете подклассы типа Foo и Bar для моделирования конструкторов типов, вы получаете новые типы.
  • В Haskell и Standard ML конструкторы типа SOME являются первоклассными функциями, которые строят значения того типа данных, к которому они принадлежат. Например, map SOME имеет тип 'a list -> 'список опций'. В Си++, используя подклассы для моделирования конструкторов типов, вы не получаете этой возможности.
  • В Haskell и Standard ML типы данных закрыты, поэтому никто не может добавить больше конструкторов типов без изменения исходного объявления, а компилятор может проверить при компиляции, что шаблон соответствует всем случаям. В C++ нужно хорошо постараться ограничить, кто может разбивать базовый класс на подклассы.

В конце концов, получаете ли вы достаточную выгоду от симулированного совпадения по шаблону по сравнению с более типичным использованием полиморфизма на Си++? Стоит ли использовать макросы, чтобы сделать симулированное совпадение паттернов немного более кратким (в то время как запутывая его для всех остальных, кто читает ваш код)?

5
ответ дан 6 December 2019 в 06:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: