Подтвердить что ты не робот

Как избежать столкновения имен с макросами, определенными в заголовочных файлах Windows?

У меня есть код С++, который включает в себя метод под названием CreateDirectory(). Раньше в коде использовались только STL и Boost, но мне недавно пришлось включить <windows.h>, чтобы я мог искать CSIDL_LOCAL_APPDATA.

Теперь этот код:

filesystem.CreateDirectory(p->Pathname()); // Actually create it...

Больше не компилируется:

error C2039: 'CreateDirectoryA' : is not a member of ...

Что соответствует этому макросу в winbase.h:

#ifdef UNICODE
#define CreateDirectory  CreateDirectoryW
#else
#define CreateDirectory  CreateDirectoryA
#endif // !UNICODE

Препроцессор переопределяет мой вызов метода. Есть ли возможный способ избежать этого столкновения имен? Или мне нужно переименовать мой метод CreateDirectory()?

4b9b3361

Ответ 1

Вам будет лучше, если вы просто переименуете свой метод CreateDirectory. Если вам нужно использовать API окон, борьба с Windows.h - проигрышная битва.

В противном случае, если вы были совместимы с Windows.h, это все равно будет компилироваться. (хотя у вас могут быть проблемы в других местах).

Ответ 2

#undef CreateDirectory

Ответ 3

Вы можете создать модуль, единственная цель которого - #include <windows.h> и посмотреть CSIDL_LOCAL_APPDATA, завернутый в функцию.

int get_CSIDL_LOCAL_APPDATA(void)
{
    return CSIDL_LOCAL_APPDATA;
}

btw, хорошо сделано для того, чтобы выяснить, что произошло!

Ответ 4

Как разработчик, работающий на базе кросс-платформенных кодов, это проблема. Единственный способ справиться с этим -

  • убедитесь, что windows.h - по крайней мере в Windows - универсально включен. Затем макрос CreateDirectory определяется в каждом из ваших блоков компиляции и универсально заменяется CreateDirectoryW. Предварительно скомпилированные заголовки идеально подходят для этого.

ИЛИ, если это неприятное предложение (и это для меня)

  • изолировать использование windows.h в специальных файлах Windows. Создавайте файлы, которые экспортируют основные требуемые функции. Файлы заголовков должны использовать типы данных, которые совместимы, но НЕ зависят от включения windows.h. Файл реализации cpp должен (очевидно) использовать windows.h.

Если ваши функции utlility должны включать файлы заголовков проекта с конфликтующими символами, тогда необходим следующий шаблон:

#include <windows.h>
#ifdef CreateDirectory
#undef CreateDirectory
#endif
// etc
#include "some_class_with_CreateDirectory_method.h"
// ...

Затем вам нужно будет явно вызвать не-макроверсию любых функций windows api, которые у вас есть # undef'd - CreateDirectoryA или W и т.д.

Ответ 5

push macro, undef it и pop макрос снова:

#pragma push_macro("CreateDirectory")
#undef CreateDirectory
void MyClass::CreateDirectory()
{
 // ...
}
#pragma pop_macro("CreateDirectory")

Ответ 6

Обратите внимание, что конфликт имен обычно происходит из определенного заголовочного файла, который включен. До тех пор такие вещи, как CreateDirectory и GetMessage, не попадают в видимость, а компиляция кода без проблем.

Вы можете выделить такое включение в заголовочный файл обертки и "#undef whatever" в конце. Тогда, какое бы имя у вас не было, уйдет. Если, конечно, вам не нужно использовать эти макросы в своем собственном коде (да, очень вероятно...)

Ответ 7

#pragma push_macro("CreateDirectory")

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