Макро Stringify с строковым литералом Unicode

Я использую этот макрос препроцессора, чтобы «stringify» и легко возвращался из функции разрешения определений:

#define STRINGIFY_RETURN(x) case x:     return #x ""

Это работает как очарование в среде MBSC с обычными строковыми литералами. Пример:

#define MY_DEFINE_1 1
#define MY_DEFINE_2 2
#define MY_DEFINE_3 3

const char* GetMyDefineNameA(unsigned int value)
{
switch(value)
{
STRINGIFY_RETURN(MY_DEFINE_1);
STRINGIFY_RETURN(MY_DEFINE_2);
STRINGIFY_RETURN(MY_DEFINE_3);
default:    return "Unknown";
}
}

Однако мне приходилось все больше и больше переключаться на совместимость с Юникодом, и поэтому мне пришлось переписывать эту функцию, чтобы вернуть строки Юникода, которые требуют префикса с L перед строковыми литералами. Итак, я попробовал:

#define STRINGIFY_RETURN_WIDE(x)    case x:     return #x L""
const wchar_t* GetMyDefineNameW(unsigned int value)
{
switch(value)
{
STRINGIFY_RETURN_WIDE(MY_DEFINE_1);
STRINGIFY_RETURN_WIDE(MY_DEFINE_2);
STRINGIFY_RETURN_WIDE(MY_DEFINE_3);
default:    return L"Unknown";
}
}

Но это дает мне ошибки:

ошибка C2308: конкатенация несоответствующих строк

ошибка C2440: «возврат»: невозможно преобразовать из «const char [12]» в «const wchar_t *»

Я также попробовал:

#define STRINGIFY_RETURN_WIDE(x)    case x:     return L #x ""#define STRINGIFY_RETURN_WIDE(x)    case x:     return #x "" L

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

Я был бы очень признателен, если бы кто-то мог показать правильный способ сделать этот макрос так, чтобы он преобразовывался в строковый литерал Unicode.

Обновить:

#define STRINGIFY_RETURN_WIDE(x)    case x:     return L#x ""

не выдает ошибку C2440, но все равно дает мне C2308.

Обновление 2:

Я использую Microsoft Visual Studio 2013

8

Решение

У вас есть два основных варианта:

#define STRINGIFY_RETURN_WIDE(x) case x: return L#x L""

Это объединяет два L"…" строки. Альтернативное и более простое решение — не объединять пустую строку:

#define STRINGIFY_RETURN_WIDE(x) case x: return L#x

Не ясно, есть ли польза от добавления пустой строки.


Как Роберт Прево отметил в комментарий, это не работает с G ++ и Clang ++,
хотя, кажется, работает на Vinzenz с его компилятором (Microsoft Visual Studio 2013).

Проблема в том, что препроцессор токенизирует свой ввод и широкий строковый литерал L"..." все это один токен, но макрос выше пытается генерировать токены L и «…», что приводит к проблемам:

xx11.cpp:5:49: error: ‘L’ was not declared in this scope
#define STRINGIFY_RETURN_WIDE(x) case x: return L#x
^
xx11.cpp:11:9: note: in expansion of macro ‘STRINGIFY_RETURN_WIDE’
STRINGIFY_RETURN_WIDE(MY_DEFINE_1);

Существует обходной путь:

#define MY_DEFINE_1 1
#define MY_DEFINE_2 2
#define MY_DEFINE_3 3

#define LSTR(x) L ## x
#define STRINGIFY_RETURN_WIDE(x) case x: return LSTR(#x)

const wchar_t* GetMyDefineNameW(unsigned int value)
{
switch(value)
{
STRINGIFY_RETURN_WIDE(MY_DEFINE_1);
STRINGIFY_RETURN_WIDE(MY_DEFINE_2);
STRINGIFY_RETURN_WIDE(MY_DEFINE_3);
default:    return L"Unknown";
}
}

Проверено на Mac OS X 10.11.6 с GCC 6.2.0.

6

Другие решения

http://en.cppreference.com/w/cpp/preprocessor/replace

Показывает, что:

#define showlist(...) puts(#__VA_ARGS__)
showlist();            // expands to puts("")
showlist(1, "x", int); // expands to puts("1, \"x\", int")

Поскольку расширение включает в себя кавычки, я думаю, просто возвращение L # x будет желаемым результатом для широких символов.

2

По вопросам рекламы [email protected]