可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have some C++ code that includes a method called CreateDirectory().
Previously the code only used STL and Boost, but I recently had to include <windows.h>
so I could look-up CSIDL_LOCAL_APPDATA
.
Now, this code:
filesystem.CreateDirectory(p->Pathname()); // Actually create it...
No longer compiles:
error C2039: 'CreateDirectoryA' : is not a member of ...
Which corresponds to this macro in winbase.h
:
#ifdef UNICODE
#define CreateDirectory CreateDirectoryW
#else
#define CreateDirectory CreateDirectoryA
#endif // !UNICODE
The pre-processor is redefining my method call. Is there any possible way to avoid this naming collision? Or do I have to rename my CreateDirectory()
method?
回答1:
You will be better off if you just rename your CreateDirectory method. If you need to use windows APIs, fighting with Windows.h is a losing battle.
Incidently, if you were consistent in including windows.h, this will still be compiling. (although you might have problems in other places).
回答2:
回答3:
You could create a module whose sole purpose is to #include <windows.h>
and look up CSIDL_LOCAL_APPDATA wrapped in a function.
int get_CSIDL_LOCAL_APPDATA(void)
{
return CSIDL_LOCAL_APPDATA;
}
btw, Well done for working out what happened!
回答4:
As a developer working on a cross platform codebase, this is a problem. The only way to deal with it is to
- ensure that windows.h is - on Windows builds at least - universally included. Then the CreateDirectory macro is defined in every one of your compilation units and is universally substituted with CreateDirectoryW. Precompiled headers are ideal for this
OR, if that is an unpleasant proposition, (and it is for me)
- isolate windows.h usage into windows specific utility files. Create files that export the basic required functionality. The header files must use data types that are compatible with, but do NOT depend on the inclusion of windows.h. The cpp implementation file must (obviously) use windows.h.
If your utlility functions need to include project header files with conflicting symbols then the following pattern is a necessity:
#include <windows.h>
#ifdef CreateDirectory
#undef CreateDirectory
#endif
// etc
#include "some_class_with_CreateDirectory_method.h"
// ...
You will need to then explicitly call the non macro version of any windows api functions you have #undef'd - CreateDirectoryA or W etc.
回答5:
push
macro, undef
it and pop
the macro again:
#pragma push_macro("CreateDirectory")
#undef CreateDirectory
void MyClass::CreateDirectory()
{
// ...
}
#pragma pop_macro("CreateDirectory")
回答6:
Note that name conflict usually comes from a certain header file being included. Until then stuff like CreateDirectory and GetMessage isn't pulled into visibility and code compiles without a problem.
You can isolate such an inclusion into a wrapper header file and "#undef whatever" at its end. Then, whatever name collision you have will be gone. Unless, of course, you need to use those macros in your own code (yeah, so very likely...)
回答7:
You can take a back up of CreateDirectory
, then undefine it, and then define it again when you finish your job with you custom one.
#ifdef CreateDirectory
#define CreateDirectory_Backup CreateDirectory
#undef CreateDirectory
#endif
// ...
// Define and use your own CreateDirectory() here.
// ...
#ifdef CreateDirectory_Backup
#define CreateDirectory CreateDirectory_Backup
#undef CreateDirectory_Backup
#endif
回答8:
#pragma push_macro("CreateDirectory")
If nothing works, instead of renaming you could use your own namespace for your functions.