макрос C ++, использующий переменную из другого макроса - PullRequest
0 голосов
/ 22 марта 2020

Мне нужно сделать компиляцию foo, реализовав для нее макросы:

int foo(std::string tag)
{
    SWITCH_STRING(tag)
    {
        STRING_CASE(a)
        {
            return 1;
        }

        STRING_CASE(b)
        {
            return 2;
        }

        STRING_CASE(abc)
        {
            return 3;
        }

        STRING_ELSE
        {
            return -1;
        }
    }
}

Я хотел бы использовать параметр tag в SWITCH_STRING(tag) и сравнить его с параметром letter в STRING_CASE(letter), чтобы реализовать этот переключатель как синтаксис, я застрял на некоторое время и новичок в макросах в c ++. Не могли бы вы предложить решение о том, как реализовать макросы, пожалуйста?

#include <iostream>
#include <string>

// Write macros here | 
#define SWITCH_STRING(tag)
#define STRING_CASE(letter) letter == tag ? true : false
#define STRING_ELSE

Ответы [ 2 ]

1 голос
/ 23 марта 2020

Я должен признать: макросы могут быть веселыми. Мы все должны знать, что их следует избегать. Хотя, поскольку это упражнение о макросах, мы можем обсудить, использовать макрос или нет.

Смысл упражнения в том, что вы не можете (напрямую) включить std::string. Этот ответ показывает, как можно обойти это ограничение. Необходимый для написания чрезвычайно подробного повторяющегося кода макрос оправдан. Для полноты картины я хочу добавить, как это можно решить, используя ваш оригинальный подход, используя серию if вместо switch.

Во-первых, я пишу функцию, которая выполняет то, что запрашивается, без какого-либо макроса:

int foo(std::string tag)
{
    std::string& temp = tag;
    {
        if (temp == "a") 
        {
            return 1;
        }
        if (temp == "b")
        {
            return 2;
        }
        if (temp == "abc")
        {
            return 3;
        }
        {
            return -1;
        }
    }
}

Это не очень хорошо, что он использует if s, а не else if, что должно быть предпочтительнее для взаимоисключающих случаев. Однако, как и в каждом случае return s, результат не будет отличаться (если это не так, вам придется добавить goto vodoo, как указано в другом ответе). Имея это, легко увидеть, какие макросы нужны:

#define SWITCH_STRING(tag) std::string& temp = tag;
#define STRING_CASE(X) if (temp == #X)
#define STRING_ELSE

Этот тип ответа на ваш вопрос о том, как использовать параметр одного макроса во втором: вы этого не делаете. Вместо этого вы можете использовать ссылку, имя которой больше не зависит от фактического имени tag.

Полный пример

1 голос
/ 22 марта 2020

Что вы можете сделать, чтобы включить строку:

constexpr std::size_t myhash(std::string_view) { /* .. */ }

int foo(const std::string& tag)
{
    switch (tag)
    {
        case myhash("a"): { return 1; }
        case myhash("b"): { return 2; }
        case myhash("abc"): { return 3; }
        default: { return -1; }
    }
}

Это не требует MACRO.

Если у вас есть коллизии с вашими делами, компиляция не удалась (то же значение в switch) и вам понадобится еще одна функция ha sh.

Если вы хотите предотвратить столкновения (из входной строки), вы можете сделать:

constexpr std::size_t myhash(std::string_view) { /* .. */ }

int foo(const std::string& tag)
{
    switch (tag)
    {
        case myhash("a"): { if (tag != "a") { goto def; } return 1; }
        case myhash("b"): { if (tag != "b") { goto def; } return 2; }
        case myhash("abc"): { if (tag != "abc") { goto def; } return 3; }
        default: { def: return -1; }
    }
}

, что может быть меньше Подробно с MACRO

#define CaseHash(str, c) case myhash(c): if (str != c) { goto def; }
#define DefaultHash default: def

, чтобы получить

constexpr std::size_t myhash(std::string_view) { /* .. */ }

int foo(const std::string& tag)
{
    switch (tag)
    {
        CaseHash(tag, "a") { return 1; }
        CaseHash(tag, "b") {  return 2; }
        CaseHash(tag, "abc") {  return 3; }
        DefaultHash: { return -1; }
    }
}
...