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


Коротко - никак. Только для фундаментальных вроде int/char/enum можно.

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

switch(*a){

Ага, пробуем скомпилить:

#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:10: error: case label does not reduce to an integer constant switch.cpp:12: error: case label does not reduce to an integer constant

ShTH
() автор топика
Ответ на: комментарий от Elverion

А если строки нужно сравнивать, то можно по хешам свитч делать.

Elverion
()

Самое интересное, что в макроаасемблерах обычно больше можно было, и со сладким синтаксисисом.

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

>> хешики сравнивай

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

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

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

Ладно, буду использовать нагромождения из конструкций if(), else if(). Проект не большой, просто учусь писать и использовать классы.

ShTH
() автор топика
Ответ на: комментарий от ShTH
    void Npc::damage(int damage_type, int damage_sum){


    switch(damage_type){
        case 1:
        cout << "Урон SMG. Одно попадание забирает 5 очков. Попаданий:" << damage_sum  << endl;
        health -= (5 * damage_sum);
        break;

        case 2:
        cout << "Урон AR2. Одно попадание забирает 9 очков. Попаданий:" << damage_sum << endl;
        health -= (9 * damage_sum);
        break;

        default:
            cerr << "!!!!|       Оружие не известно! Ошибка" << endl << endl;
        break;
        }

}

Хотел как damage_type указывать не номера, а слова, например «ar2».

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

>Хотел как damage_type указывать не номера, а слова, например "ar2".

Enum для этого и сделан

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

Хватит быдлокодить. На самом деле в c++ switch для char не нужен.

madcore ★★★★★
()

switch не нужен. Юзай полиморфизм или ассоциативные контейнеры

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

>> Хотел как damage_type указывать не номера, а слова, например "ar2".

>это неправильное желание

В Qt вроде бы по такому принципу сигналы диспатчатся.

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

Диспатч он вообще всегда так работает. Сравниением строк...

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

Потому что это сравнение строк. Которое требует дофига операций. Когда строки будут символов под сто, а условий будет под сотню, а вызовов в секунду будет...

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

>Ладно, буду использовать нагромождения из конструкций if(), else if(). Проект не большой, просто учусь писать и использовать классы.

Не совсем ясна задача.

Если на входе слова из известного словаря и требуется очень быстрая обработка, то следует использовать любую библиотеку вычисления perfect hash.

Если требования по скорости более низкие или словарь заранее неизвестен, то можно использовать дерево поиска.

Если требований по скорости нет вообще - то можно использовать последовательный перебор строк. Например, можно хранить нужные слова в массиве вместе с указателеми на функцию обработки.

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

Поясню. Как такая конструкция:

switch(a%4) {
case 0:
do_smth;
{
case 2:
do_smt2;
{
case 4:
do_smt3;
}
}
}

Имхо в этом и проблема понимая switch.

namezys ★★★★
()

Вариант: взять дистанцию левенштейна, и свитч делать уже по ней :)

dannie
()

Это development

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

>Как такая конструкция

мне вот просто интересно - а что ты, собственно, хотел этой конструкцией сказать? что switch - это такой goto? что в нём можно забыть написать break? или что-то третье?

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

вот и займись этим

Заколебали. Вот идея. Именно этот код не тестировал, но рабочая 100%:

#include <boost/mpl/vector.hpp>
#include <boost/mpl/begin.hpp
#include <boost/mpl/deref.hpp>

#define ADDCASE(Name, Label, Function) \
class Name\
{\
public:\
String label_;
Name() : label_(Label){}\
void execute() { Function(); return true; }\
};

Потом в коде:

void function1()
{ printf("Hello from switch"); }

ADDCASE(CASEBLOCK1, "label1" , function1)

И так - сколько нужно кейсов.

Потом кладем кейсы в контейнер:

typedef boost::mpl::vector<CASEBLOCK1, CASEBLOCK2, CASEBLOCK3> CASES;

Сам свитч:

template <class Begin, class End>
struct SWITCH
{
static bool doswitch(const String& s)
{
  typedef typename boost::mpl::deref<Begin>::type deref;
  dereft ex;
  if( ex.label_ == s )
    return ex.execute();
  else
    return Iteratorhelper<typename boost::mpl::next<Begin>::type, End >::doswitch(s); 
}
};

template <class End>
struct SWITCH<End, End>
{
static  bool doswitch(const String& s)
{
  bool false;
}
};

template<typename Container>
static QString PERFORMSWITCH(const String& s)
{
return SWITCH<typename boost::mpl::begin<Container>::type, typename boost::mpl::end<Container>::type>::switch(s);
}

Как пользоваться:

PERFORMSWITCH<CASES>("blabla");

Теперь компилятор сгенерит нам статическую функцию PERFORMSWITCH<CASES>, которая будет то же самое, что много if/else, но куда проще для расширения, доработки, создания новых кейсов.

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

>которая будет то же самое

что и сравнение по хешикам, с той лишь разницей, что ты их считаешь статически (рукми объявляешь все CASEBLOCK'и). расширяемость, читаемость (как реализации так и использования), зависимости - всё на уровне плинтуса. вопорос дня: а в чём профит-то?

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

что и сравнение по хешикам

Нет, в данном случае будет вызываться оператор сравнения для строки. Можно и хэши сделать (если постараться, то и статические). В doswitch можно делать все, что хочешь.

Читаемость отличная. Профит в том, что компилятор напишет за тебя очень много кода (и сделает это оптимально), скорости, расширяемости. Сам свитч можно вынести в отдельный хидер. Тогда для написания новых свитчей тебе достаточно сделать

void function1() { printf("Hello from switch"); }
void function2() { printf("Hello from switch"); }

ADDCASE(CASEBLOCK1, "label1" , function1) 
ADDCASE(CASEBLOCK2, "label2" , function1) 
ADDCASE(CASEBLOCK3, "label3" , function2) 

void test( )
{
...
typedef boost::mpl::vector<CASEBLOCK1, CASEBLOCK2, CASEBLOCK3> CASES2;
String mystr("label3");
PERFORMSWITCH<CASES2>(mystr);
...
}

Отличная читаемость, отличная расширяемость. И самое главное - это только идея, можно очень красиво ее доработать.

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

Это как? Так?

(defgeneric switch-test (switch-case value)
            (:method (x y) (equal x y))
            (:method ((switch-case (eql T)) value) T))

(defmacro switch (value &rest cases)
  (let ((value-var (gensym)))
    (labels ((process-switch (cases)
               (if (null cases)
                 nil
                 (destructuring-bind
                   ((current-case &body body) &rest cases) cases
                   `(if (switch-test ,current-case ,value-var)
                      (progn ,@body)
                      ,(process-switch cases))))))
      `(let ((,value-var ,value))
         ,(process-switch cases)))))

(use-package :cl-ppcre)

(defstruct regex (pattern ".*" :type string))

(set-dispatch-macro-character
  #\# #\" (lambda (s c n)
            (declare (ignore n))
            (unread-char c s)
            `(make-regex :pattern ,(read s t nil t))))

(defmethod switch-test ((case-of regex) (value string))
  (cl-ppcre:scan (regex-pattern case-of) value))

(defun main (s)
  (switch s
    (#"(?i)[A-Z]" (format t "String contains letters~%"))
    (#"[0-9]" (format t "String contains at least one digit and no letters~%"))
    (T (format t "The value is not a string"))))

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

между вторым и третьим случаями туда неплохо бы "(#".*" (format t "String contains no letters or digits"))", но суть и так понятна, думаю :)

Love5an
()

если один символ, то

#include <iostream> 

using namespace std;

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

    switch(*a) {                  /* или a[0] вместо *a */
      case 'a': 
        cout << "a = a" << endl; 
        break; 
      
      case 'b': 
        cout << "a = b" << endl; 
        break; 
    } 
}
ono
()
Ответ на: комментарий от Absurd

Оптимально построить finite state machine по данным строкам на этапе компиляции. Она будет небольшой, и поиск будет занимать O(N) (N - длина входной строки) или даже меньше.

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

> Уййййоооооо...

Что не так?

Вдогонку: вместо [code] return Iteratorhelper<typename boost::mpl::next<Begin>::type, End >::doswitch(s); [/code] следует читать [code] return SWITCH<typename boost::mpl::next<Begin>::type, End >::doswitch(s); [/code]

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

> Оптимально построить finite state machine

Какие мы умные. Конечно можно, но делать ты это будешь приблизительно так же. Только добавится еще функция, возвращающая указатель на себя же.

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

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

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

В лиспе можно сделать при желании примерно так:

(case (var)
  ("abc[de]+f" 'first-string)
  ("abc[fg]" 'second-string)
  (else 'third))

В С++ без препроцессора я бы не стал этого делать вообще (если только не очень жётские требования к производительности). В D можно сделать.

А говорить про твоё нагромождение капслока, что оно отлично читается - нельзя.

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

Капслок здесь необязателен, препроцессор для удобства. Это вообще демонстрация идеи. И неоптимальная, за счет создания временного объекта.

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

Не смотрел реализацию тикля, но мой комментарий относился не конкретно к тиклю, и компиляции там ничего не мешает. Вообще реализация case-а по строкам с использованием FSM идеологически очень похожа на реализацию case-а с использованием таблицы переходов.

Legioner ★★★★★
()

В полку индусов прибыло. Зачем вы за этот switch зацепились. Нагородите всяких макросов, шаблонами все обложите, и тот кто будет разбирать ваш код после вас, будет яростно писать кипятком. Чем плох такой вариант?

inline bool _IsEqu(const char* s1,const char* s2) { return (strcmp(s1,s2)==0); };

void Process(const char* text)
{
	if(_IsEqu(text,"aaa"))
	{
		//do some ...
	}
	else if(_IsEqu(text,"bbb"))
	{
		//do some ...
	}
	else if(_IsEqu(text,"ccc"))
	{
		//do some ...
	}
	else
	{
		pAnIc();
	}
}
З.Ы. Без _IsEqu можно было обойтись, но мне кажется, что так легче читается, а назначение этой функции можно понять из названия.

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

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


void Process(const char* text)
{
if(_IsEqu(text,"aaa"))
{
//do some ...
}
else if(_IsEqu(text,"bbb"))
{
//do some ...
}
else if(_IsEqu(text,"ccc"))
{
//do some ...
}
else if(_IsEqu(text,"ccc"))
{
//do some ...
}
else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
}
{
//do some ...
} else if(_IsEqu(text,"ccc"))
{
//do some ...
}
else
{
pAnIc();
}
}

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