2011-01-20 8 views
18

Próbuję wygenerować nazwę pliku włączającego w makrze. To ma być prawnym w C++:Generowanie nazwy pliku włączającego w makrze

#define INCLUDE_FILE "module_impl_win.hpp" 
#include INCLUDE_FILE 

to działa dobrze, ale jak tylko próbuję generowanej nazwy pliku to failes skompilować

#define INCLUDE_FILE(M) M##"_impl_win.hpp" 
#include INCLUDE_FILE("module") 

Właściwie to daje mi ostrzeżenie na MSVC2010

warning C4067: niespodziewane tokeny następujące dyrektywy preprocesora - oczekiwać NEWLIN

, ale nie uwzględnia pliku.

Na czym polega problem? Jak mogę się go pozbyć?

Odpowiedz

18

Zrobiłbym to za pomocą pomocnika powołującego się na makro. Coś takiego da Ci to, co chcesz:

#define QUOTEME(M)  #M 
#define INCLUDE_FILE(M) QUOTEME(M##_impl_win.hpp) 

#include INCLUDE_FILE(module) 
+1

Trzeba być ostrożnym z tym podejściem.'_impl_win' jest tokenem identyfikatora, a ponieważ zaczyna się od podkreślenia (i znajduje się w przestrzeni nazw makr), jest zarezerwowane dla implementacji. Powinieneś odciąć wiodące '_' i połączyć je oddzielnie, ale poza tym nie jestem pewien jak to zrobić, ponieważ' _' sam jest zarezerwowanym identyfikatorem. –

+1

BTW, jak to jest przenośne? – ledokol

+0

@ James McNellis: Standard zastrzega sobie tylko nazwy z podkreśleniem, a następnie wielką literą (lub nazwami zawierającymi podwójne podkreślenie). Nie wiem, dlaczego Sutter zaleca unikanie wszędzie podkreślenia. – ledokol

3

Problem polega na tym, że w końcu Twój kod będzie wyglądać następująco:

#include "module""_impl_win.hpp" 

To generuje ostrzeżenie i błędów sam widzisz, ale w nieco bardziej oczywisty sposób.

Podczas gdy kompilator zaakceptuje tę składnię, preprocesor nie będzie.

Nie mam sugestii, aby wykonać to, co próbujesz wykonać. Osobiście nie chciałoby używać tego typu makr, ponieważ utrudnia nawigację kodu wizualnie i prawdopodobnie uniemożliwi wielu redaktorom szybkie poruszanie się po kodzie.

+0

Dzięki, nie wiedziałem, że łączy takie ciągi. Wyobraź sobie, że istnieje setka plików, które zawierają nagłówki specyficzne dla platformy z #ifdef ... #endif. Jeśli jutro dodam obsługę jeszcze jednej platformy, będę musiał edytować wszystkie te pliki, zamiast tylko edytować jedno makro i dodawać pliki implementacyjne specyficzne dla platformy. To smutne. – ledokol

+0

@ledokol: Dlaczego funkcja specyficzna dla platformy nie może zostać podzielona na osobne nagłówki i pliki źródłowe, które nie są zawarte w innych miejscach? Powinno być łatwo skonsolidować funkcje zależne od platformy i platformy w stosunkowo niewielkim zestawie plików. –

+0

Masz na myśli, dlaczego PIMPL nie jest używany do oddzielania kodu specyficznego dla platformy? Cóż, nie można go używać wszędzie. Istnieje wiele klas szablonów, które wymagają deklaracji klasy implementacji specyficznej dla platformy. Muszę więc podzielić go na pliki nagłówkowe i pliki implementacji. – ledokol

3

Można również użyć Zwiększ preprocesor, zwłaszcza BOOST_PP_STRINGIZE/BOOST_PP_CAT makra:

#include <boost/preprocessor/cat.hpp> 
#include <boost/preprocessor/stringize.hpp> 

#define INCLUDE_FILE(M) BOOST_PP_STRINGIZE(BOOST_PP_CAT(M, _impl_win.hpp)) 

// expands to: #include "module_impl_win.hpp" 
#include INCLUDE_FILE(module) 

(por C Macro - DynamiC#include)

pamiętać, że ta cierpi na ten sam problem, co odpowiedź @ Andrew'a (prowadząc znak podkreślenia = zarezerwowany identyfikator).