Допустим, я реализую простую оболочку вокруг ExpandEnvironmentStringsW :
// ExpandNStuff.hpp:
#include <string>
namespace WindowsApi
{
std::wstring ExpandEnvironmentStrings(const std::wstring& source);
}
// ExpandNStuff.cpp:
#include <windows.h>
#include "ExpandNStuff.hpp"
#include "Win32Exception.hpp"
namespace WindowsApi
{
std::wstring ExpandEnvironmentStrings(const std::wstring& source)
{
DWORD len;
std::wstring result;
len = ::ExpandEnvironmentStringsW(source.c_str(), 0, 0);
if (len == 0)
{
THROW_LAST_WINDOWS_ERROR();
}
result.resize(len);
len = ::ExpandEnvironmentStringsW(source.c_str(), &result[0], len);
if (len == 0)
{
THROW_LAST_WINDOWS_ERROR();
}
result.pop_back(); //Get rid of extra null
return result;
}
}
Ничего страшного - все имеет смысл до этого момента.Посмотрите, что произойдет, когда я добавлю main.cpp
:
#include <iostream>
#include <string>
#include "ExpandNStuff.hpp"
int main()
{
std::wstring source(L"Hello World! Windows is in %WINDIR%");
std::wstring expanded(WindowsApi::ExpandEnvironmentStrings(source));
std::wcout << expanded << std::endl;
}
Сюрприз!Этот код не будет ссылаться.Причина в том, что в модуле перевода ExpandNStuff.cpp
заголовок windows.h
определил ExpandEnvironmentStrings
как ExpandEnvironmentStringsW
, используя макрос, несмотря на тот факт, что мы попытались сделать нашу реализацию отличной, поместив ее в пространство имен.Поэтому модуль перевода ExpandNStuff.cpp
считает, что функция называется WindowsApi::ExpandEnvironmentStringsW
, а не WindowsApi::ExpandEnvironmentStrings
, как ожидает автор.Но блок перевода main.cpp
не #include <windows.h>
, поэтому его имя не совпадает с именем в блоке перевода ExpandNStuff.cpp
.
Исправление заключается в добавлении этого в ExpandNStuff.hpp
:
#ifdef ExpandEnvironmentStrings
#undef ExpandEnvironmentStrings
#endif
Однако выполнение этого для каждого API может быть утомительным.Я бы просто был вынужден вызывать версию функции "W" или "A" явно, чем быть укушенным #define
ошибками вроде этой.Есть ли способ отключить макросы?