LINUX.ORG.RU

[c++][switch] как юзать свитч для char *?

 ,


0

0

Я считаю, что вопрос не достоин девелопмента, потому запостил сюда.

Вот пример кода:

#include <iostream>
using namespace std;

int main(){
const char *a = "b";


switch(a){

    case "a":
        cout << "a = a" << endl; break;
    case "b":
        cout << "a = b" << endl; break;
    }
}


А компилятор какбы говорит: switch.cpp:8: error: switch quantity not an integer


Ответ на: комментарий от lester

>> скоростью работы

во-первых, а оно нам надо?

во-вторых, цифры в студию, а не размышления о компиляторе cpp в вакууме который сгенерит нам шарообразный код.

и третье: ещё буста не хватало ради такого задротства якобы улучшающего читабельность.

deadman ★★
()
Ответ на: комментарий от deadman

> во-первых, а оно нам надо?

вам - нет

> во-вторых, цифры в студию, а не размышления о компиляторе cpp в вакууме который сгенерит нам шарообразный код.


это очевидно, если не верите - сравните сами

> и третье: ещё буста не хватало ради такого задротства якобы улучшающего читабельность.


какого буста, вы о чем?

lester ★★★★
()
Ответ на: комментарий от pathfinder

>Чем плох такой вариант?

На самом деле после каждого strcmp() можно отсекать половину заведомо неправильных вариантов, заменяя O(N) на O(log N). Но ручками балансировать проверки хлопотно и багоопасно, и поэтому мы обращаемся к потрясающе мощным средствам плюсового метапрограммирования. Такие дела.

Absurd ★★★
()
Ответ на: комментарий от loveless

Сделать лучше несложно. Кто решит такую задачу - молодец.

Надо всего-то отсортировать список типов по названию, а потом соорудить из него что-то вроде

switch(strcmp(MEDIUM_TYPE.value(), str)) {
case 0:
  medium_type_op();
  break;
case 1:
  switch(strcmp(LEFT_MEDIUM_TYPE.value(), str)) {
   ...same here...
  }
  break;
case -1:
  switch(strcmp(RIGHT_MEDIUM_TYPE.value(), str)) {
   ...same here...
  }
  break;
}
Absurd ★★★
()
Ответ на: комментарий от xintrea

> Я не понял, а что, с одинарными кавычками не прокатит?

Конечно нет. Слова то будут русскими. Надо "ёлочки" использовать.

LamerOk ★★★★★
()

Во-первых, естественно само собой разумеется, если возможно, то строкам надо предпочитать енумы. Эти охеренно быстро и компилятор просто увьётся около тебя, стремясь угодить и подсказать (например о том, что в свиче не все варианты енума проверены). Однако если так сильно свербит использовать строки, и если их (и действий) больше трёх - то советую использовать массив пар строка+указатель_на_функцию. Тут сплошные профиты: отсутствие огромной спагетти-функции, никакого риска запутаться в скобках, возможность при необходимости прикрутить хеширование или поиск пополамом. Но всётаки, подумай об енумах.

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

>Во-первых, естественно само собой разумеется, если возможно, то строкам надо предпочитать енумы. Эти охеренно быстро и компилятор просто увьётся около тебя, стремясь угодить и подсказать (например о том, что в свиче не все варианты енума проверены).

Совершенно типичное неумение любителя С++ размышлять в духе конструктивизма, то есть рассматривать контексты для которых известен способ их получения.

Вопрос: а в каком месте проекта нужен такой диспатчинг?
Ответ: Ну например
а) При получении команды из IO обеспечить диспатчинг комманды к обработчику,
б) При написании оконного фреймворка обеспечить диспетчеризацию какого-то события от инициатора к получателю по ID события.

В случае а) комманда тебе поступает в виде строки символов и у тебя будет та же самая вермишель из strcmp() чтобы получить enum из строки символов, так что профита никакого - можно было вместо получения enum-а сразу сделать диспатчинг. В случае б) У разработчиков оконного фреймворка будет постоянный кариес с централизованной раздачей идентификатора события на каждый чих и вермишель уже в revision history.

Absurd ★★★
()
Ответ на: комментарий от Absurd

Я же сказал "если возможно". Естественно, блин, не о шелле разговор. А вермишель из strcmp() всё равно совершенно необязательна.

legolegs ★★★★★
()

ля ля ля, ня ня ня

Object subclass: Switch [
    | dict default |

    Switch class >> new [
        ^ super new init ]

    Switch class >> with [
        ^ self new ]

    init [
        dict := Dictionary new.
        default := [ nil ]
    ]

    variants: anArray [
         anArray do: [ :pair | dict at: (pair key) put: (pair value) ]]

    case: anObject [| aBlock |
        aBlock := dict at: anObject ifAbsent: [ default ].
        ^aBlock value ]

    default: aBlock [
        default := aBlock ]
]


| switch |
switch := Switch with variants: {
    12  -> [ 12 squared ].
    #a  -> [ ' a symbol ' ].
    'B' -> [ ' B follows A in English alphabet ' ].
    };
    default: [ 'something unknown' ].
st> switch case: #a
' a symbol '
st> switch case: 12
144
st> switch case: 'B'
' B follows A in English alphabet '
st> switch case: (Dictionary new)
'something unknown'
st> 
yoghurt ★★★★★
()
Ответ на: комментарий от Absurd

> комманда тебе поступает в виде строки символов и у тебя будет та же самая вермишель из strcmp() чтобы получить enum из строки символов, так что профита никакого

std::map принципиально не используем?

lester ★★★★
()
Ответ на: комментарий от yoghurt

> получить enum из строки
> А вторым шаблонным аргументом в std::map уже умеют быть лямбды?


читай внимательно

lester ★★★★
()
Ответ на: комментарий от yoghurt

> А вторым шаблонным аргументом в std::map уже умеют быть лямбды?

да и даже если так - есть указатели на функции

lester ★★★★
()
Ответ на: комментарий от lester

>> А вторым шаблонным аргументом в std::map уже умеют быть лямбды?

> да и даже если так - есть указатели на функции

Если бы с ними всё было так гладко...)) Вспомнилась глава из Александреску про Функторы, в сердце ёкнуло

yoghurt ★★★★★
()
Ответ на: комментарий от lester

>> комманда тебе поступает в виде строки символов и у тебя будет та же самая вермишель из strcmp() чтобы получить enum из строки символов, так что профита никакого

>std::map принципиально не используем?

А зачем он нужен для статической конструкции известной на момент компиляции? BTW, С глобальным мапом можно поиметь внезапный рейс-кондишен.

Absurd ★★★
()
Ответ на: комментарий от Absurd

> А зачем он нужен для статической конструкции

затем, что вариант с "switch(strcmp" пусть используют ежики, а вариант с "if(strcmp" будет медленнее

> С глобальным мапом можно поиметь внезапный рейс-кондишен.


можно все что угодно - даже на 0 поделить, если не следить за тем, что пишешь

lester ★★★★
()
Ответ на: комментарий от lester

Ну, если делать как нибудь вот так...

receiver::receiver ()
{    m_handlers [HELLO_PACKET_TYPE] = on_hello_st;
}

void receiver::process (packet *p)
{    handler_fcn = m_handlers [p->type];
     handler_fcn (this, p);
}

static void receiver::on_hello_st ( receiver *pthis, packet *p)
{    pthis->on_hello (p);
}

...то не мешает ничего =) Просто некрасиво, имхо. И не особо расширяемо

yoghurt ★★★★★
()

Празник быдлокодеров. В треде дикий бред на плюсах(очень умно объявлять ненужные функции на каждый чих, особенно хорошо будет с локальными переменными), примеры на tcl, lisp и smalltalk, на которых очевидно решение выглядит совершенно иначе и несколько советов о том как делать диспач на строках. Резюмирую - лучше всего забыть о строках и сделать enum(если нужно получать строки из внешнего мира, то еще и хеш строка <-> идентификатор, и прикрутить к этому макросы). Это самый простой и производительный вариант.

anonymous
()
Ответ на: комментарий от anonymous

> очень умно объявлять ненужные функции на каждый чих, особенно хорошо будет с локальными переменными

Легко обобщить пример для передачи содержимого контекста в виде параметров функции.

> дикий бред на плюсах

Обоснуй

loveless
()

Чем такой вариант не катит?

#define NYA 0
#define NYASKA 1
#define NEKOTAN 2

...
int test = 1;
switch ( test){
case NYA: ...;
case NYASKA: ...;
case NEKOTAN: ...;
}

}

Apkawa
()
Ответ на: комментарий от Apkawa

> Чем такой вариант не катит?

Внимание, внимание! Редкий экспонат, не пропустите! Человек, который изобрел енумы на макросах! Только на нашем лоре, в нашей славной кунсткамере!

Откуда такие идиоты берутся?

loveless
()
Ответ на: комментарий от anonymous

>примеры на tcl, lisp и smalltalk, на которых очевидно решение выглядит совершенно иначе

На самом деле в плюсах switch-а по строковым литералам нет только по причине тараканов в голове у Строуструпа. Такой switch мог бы быть настолько же эффективным как и switch по int-ам, т.к на начальных итерациях бинарного поиска достаточно сравнить один или два char-а в начале обоих строчек чтобы решить что возвращать: -1 или 1.

Absurd ★★★
()
Ответ на: комментарий от Absurd

А еще, чтобы сравнить две строки надо вызвать функцию! Ведь для работы оператора = вполне достаточно сравнить один или два char'а в начале обеих строчек...

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

>А еще, чтобы сравнить две строки надо вызвать функцию!

Си++ все равно неявно вызывает функции из libc в куче мест.

Absurd ★★★
()
Ответ на: комментарий от lester

>> Си++ все равно неявно вызывает функции из libc в куче мест.

>и?

Это значит что критерий вида "при разворачивании базовых конструкций не должно быть неявных вызовов к библиотеке" невалиден.

Absurd ★★★
()
Ответ на: комментарий от Absurd

> Это значит что критерий вида "при разворачивании базовых конструкций не должно быть неявных вызовов к библиотеке" невалиден.

тут зависит от того, рассматриваем мы с++ или с

в С этот принцип, кажется, соблюдается (за исключением main)

в плюсах и не должен соблюдаться, однако в плюсах не соблюдается принцип демократичности, а именно: те вызовы, которые получаются при разворачивании базовых конструкций, должны быть оформлены в классы и иметь возможность быть частично или полностью перегружены или заменены; однако, насколько полно этот принцип надо применять -- это вопрос

___________________________________

если же вернуться к свичу, то он *требует* хэш-функцию, которая не может быть сделана эффективно для любых ран-тайм строк (а вроде как именно на это нацеливались твои примеры?)

если же ограничиться константыми строками, то это вероятно кривой дизайн, лучше енум

www_linux_org_ru ★★★★★
()

Вот быдлокодеров понесло.

anonymous
()
Ответ на: комментарий от Absurd

Давай я посвечу тебе лучом истины - в мире существует чуть более одной реализации С++, не говоря уже о программах не содержащих ни единого вызова libc.

LamerOk ★★★★★
()

ВНЕЗАПАНО: полиморфизм!

Линуксоиды идут дальше править конфиги и не лезут больше в программирование. Это разные вещи.

anonymous
()
Ответ на: комментарий от www_linux_org_ru

>> Это значит что критерий вида "при разворачивании базовых конструкций не должно быть неявных вызовов к библиотеке" невалиден.

>в С этот принцип, кажется, соблюдается (за исключением main)

Сейчас, во времена x86_64 и SSE* соблюдается. Во времена стандартизации С89 похоже все реализации грешили вставкой внезапных библиотечных вызовов в вычислениях на 64-битовых целых и на плавающей точке(*). Хотя в идеале конечно всего можно было бы достичь сдвигами и маскированием.

>если же вернуться к свичу, то он *требует* хэш-функцию

Все серьезные реализации switch()-а в С/C++ балансируют jmp-ы и таким образом используют бинарный O(log N) поиск. Естественно было бы ожидать бинарный поиск и для для сравнения стрингов. А для бинарного поиска хеш-функция не нужна.

>если же ограничиться константыми строками

Строки-ключи естественно константные и лежат в .const ввместе с другими литералами. Зачем нужна константность параметру switch-a я что-то не понимаю.

(*) Прим. для небыдлокодеров - речь идет о элементарных операциях типа умножения и деления, не о синусе или логарифме.

Absurd ★★★
()
Ответ на: комментарий от anonymous

>ВНЕЗАПАНО: полиморфизм!

Полиморфизм в С++ нужен чтобы в корне сделать единственный виртуальный метод наподобие sendMessage(MsgId msgId, Variant attachment). Неэстетично зато дешево, надежно и практично. И естественно, в реализации такого метода надо будет делать switch по msgId.

Absurd ★★★
()
Ответ на: комментарий от LamerOk

>А чем тебя прогневал switch по dynamic_cast'у?

Я в общем сейчас троллю чистоплюев и поэтому пишу полусерьезно.

Absurd ★★★
()

> case "a":

Где то так - case 'a':

andreyu ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.