Come evitare la collisione con nome macro definite nei file di intestazione di Windows?
Domanda
ho un po 'di codice C ++ che include un metodo chiamato CreateDirectory().
In precedenza il codice unico STL e Boost utilizzato, ma di recente ho dovuto includere <windows.h>
così ho potuto CSIDL_LOCAL_APPDATA
look-up.
Ora, questo codice:
filesystem.CreateDirectory(p->Pathname()); // Actually create it...
Non è più compila:
error C2039: 'CreateDirectoryA' : is not a member of ...
che corrisponde a questa macro in winbase.h
:
#ifdef UNICODE
#define CreateDirectory CreateDirectoryW
#else
#define CreateDirectory CreateDirectoryA
#endif // !UNICODE
La pre-processore sta ridefinendo il mio metodo di chiamata. C'è un modo possibile per evitare questa collisione di denominazione? O devo rinominare il mio metodo CreateDirectory()
?
Soluzione
Si sarà meglio se si rinomina il metodo CreateDirectory. Se è necessario utilizzare le API di Windows, combattendo con Windows.h è una battaglia persa.
Per inciso, se si dovesse coerente in compreso windows.h, questa sarà ancora la compilazione. (Anche se si potrebbe avere problemi in altri luoghi).
Altri suggerimenti
È possibile creare un modulo il cui unico scopo è quello #include <windows.h>
e cercare CSIDL_LOCAL_APPDATA avvolto in una funzione.
int get_CSIDL_LOCAL_APPDATA(void)
{
return CSIDL_LOCAL_APPDATA;
}
btw, ben fatto per lavorare fuori quello che è successo!
#undef CreateDirectory
Come sviluppatore che lavora su una croce codebase piattaforma, questo è un problema. L'unico modo per affrontare il problema è quello di
- garantire che windows.h è - su Windows costruisce almeno - universalmente compreso. Poi la macro CreateDirectory è definito in ogni uno dei vostri unità di compilazione ed è universalmente sostituito con CreateDirectoryW. intestazioni precompilate sono ideali per questo
O, se questa è una proposta sgradevole, (ed è per me)
- isolare windows.h utilizzo in Windows file di utilità specifici. Creare file che esportano la funzionalità richiesta di base. I file di intestazione devono utilizzare i tipi di dati che sono compatibili con, ma non dipendono l'inserimento di windows.h. Il file di implementazione cpp deve (ovviamente) utilizzare windows.h.
Se le funzioni utlility devono includere i file di intestazione di progetto con i simboli contrastanti quindi il seguente modello è una necessità:
#include <windows.h>
#ifdef CreateDirectory
#undef CreateDirectory
#endif
// etc
#include "some_class_with_CreateDirectory_method.h"
// ...
Sarà necessario quindi chiamare in modo esplicito la versione non macro di tutte le funzioni API di Windows si ha # undef'd -. CreateDirectoryA o W etc
push
macro, undef
e pop
di nuovo la macro:
#pragma push_macro("CreateDirectory")
#undef CreateDirectory
void MyClass::CreateDirectory()
{
// ...
}
#pragma pop_macro("CreateDirectory")
Si noti che il nome conflitto di solito proviene da un certo file di intestazione viene incluso. Fino ad allora roba come CreateDirectory e GetMessage non viene tirato in visibilità e il codice compila senza un problema.
È possibile isolare tale inclusione in un file di intestazione involucro e "#undef qualunque" al suo termine. Quindi, qualunque sia il nome che hai collisione sarà andato. A meno che, naturalmente, è necessario utilizzare le macro nel proprio codice (sì, in modo molto probabile ...)
Si può prendere un back up di CreateDirectory
, allora non definirlo, e quindi definire di nuovo quando hai finito il tuo lavoro con te personalizzato.
#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
#pragma push_macro("CreateDirectory")
Se non funziona, invece di rinominare è possibile utilizzare il proprio spazio dei nomi per le funzioni.