2016-04-08 23 views
2

Aşağıdaki önişlemci makrosuna sahibiz. Onun Doxygen C konusunda sıkıntılı ++ ve bazı şablon typedefs çünkü Doxygen belgelerle yardımcı olmak için kullanılan: X olmayan bir şablon veya yalnızca bir şablon parametresi vardır zaman iyi çalışıyorPreprocessor makro nasıl oluşturulur?

#if defined(DOXYGEN_PROCESSING) 
# define DOCUMENTED_TYPEDEF(x, y) class y : public x {}; 
#else 
# define DOCUMENTED_TYPEDEF(x, y) typedef x y; 
#endif 

. dize Foo<R ve S>,Bar ayrılır (ve belgelerine oluşturmaz) çünkü

DOCUMENTED_TYPEDEF(Foo<R,S>,Bar); 

Sonra derleme hatalara yol açar: Ancak, X eğer birden parametrelerle bir şablondur.

Preprocessor makroyu nasıl açarım?

cevap

3

Önişlemcinin bağımsız değişkenleri makroya nasıl ayrıştırdığını değiştirme yolu yoktur. Parantez içinde olmayan virgül, her zaman makro bağımsız değişkenleri ayırır. iç parantez makro genişleme görünmesi için sorun olmazsa sen yapmak mümkün olabilir ne

DOCUMENTED_TYPEDEF((Foo<R,S>), Bar); 

ama tabii bu sadece çalışır olduğunu. Kafamın üstünü hatırlamıyorum, eğer bu sizin gösterdiğiniz bağlamlarda sorunlara neden olur.

o C99 variadic makroları gerektirir bir sakınca yoktur, ekstra parantez kurtulmak için kullanabilirsiniz:

#define STRIP_PARENS(...) __VA_ARGS__ 
#if defined(DOXYGEN_PROCESSING) 
# define DOCUMENTED_TYPEDEF(x, y) class y : public STRIP_PARENS x {}; 
#else 
# define DOCUMENTED_TYPEDEF(x, y) typedef STRIP_PARENS x y; 
#endif 

DOCUMENTED_TYPEDEF((Foo<R,S>), Bar); 

ama şimdi hep ilk argüman etrafında parantez fazladan bir çift koymak zorunda DOCUMENTED_TYPEDEF.

+0

Ben sol argüman X bir deklarasyon belirtici pozisyonuna konur, çünkü sorunlara neden olur sanıyorum. C ve C++ stili bildirimlerinde, bildirim belirticileri isteğe bağlı parantezleri almaz. Ancak, beyancılar şunları yapar: “int x;” ve “int (x);” aynı şeydir. (int) x; 'cast ifadesine benziyor. – Kaz

+0

@Kaz * Her zaman * ile * P99 değişkenlikli makroları uygulayan yalnızca destekleyici derleyicilerle * ve * şablon parametrelerini içerebilen argümanın etrafına parantez koyar mısınız? Eğer öyleyse, çalışacak bir hack var. – zwol

4

Böyle gitmeyecek:

#define COMMA , 

#if defined(DOXYGEN_PROCESSING) 
# define DOCUMENTED_TYPEDEF(x, y) class y : public x {}; 
#else 
# define DOCUMENTED_TYPEDEF(x, y) typedef x y; 
#endif 

DOCUMENTED_TYPEDEF(Foo<R COMMA S>,Bar) 

Testi: Herhangi ikame gerçekleşmeden önce

 
$ gcc -E comma-macro.c 
# 1 "comma-macro.c" 
# 1 "<built-in>" 
# 1 "<command-line>" 
# 1 "comma-macro.c" 
# 9 "comma-macro.c" 
typedef Foo<R , S> Bar; 

Makro argümanı listeleri parantez ve virgül için çözümlenir. Sonra COMMA, x bağımsız değişkeninde değiştirilir ve x, makro gövdeye ikame edilir. O zaman, argüman kırma yapılır; COMMA'un bir virgül punctuator jetonu ile değiştirilmiş olması uygun değildir. Ancak, bu makro o makro tarafından oluşturulan herhangi bir makro çağrısında oluşan bağımsız değişkenler olacaktır, bu yüzden korunmaları gerekiyorsa, daha çılgın bir şey gerekir. Bir fonksiyon benzeri makro arkasında COMMA gizleyebilirsiniz

, PAIR ki: İlk bakışta

#define COMMA , 

#define PAIR(A, B) A COMMA B 

#if defined(DOXYGEN_PROCESSING) 
# define DOCUMENTED_TYPEDEF(x, y) class y : public x {}; 
#else 
# define DOCUMENTED_TYPEDEF(x, y) typedef x y; 
#endif 

DOCUMENTED_TYPEDEF(PAIR(Foo<R, S>), Bar) 

daha çekici, ama olumsuzlukları muhtemelen vardır. Daha da şaşırtılmış. Okuyucu merak ediyor, PAIR'un arkasında semantik var mı? Oysa, COMMA, anlambilimine sahip olmak için çok geniş görünüyor ve amaç, önişlemciyle savaşmaktan kaynaklanan savaş izleri olan herkes için aniden açık.

PAIR hakkında, bunu gizleyebilir ve Zwol'un yanıtındaki gibi bir sözdizimi ile sonuçlanabilir.Ama sonra DOCUMENTED_TYPEDEF'un birden fazla çeşidine ihtiyacımız var. o C99 tarzı variadic makrolarıyla yapılabilir olabilir gibi

#define PAIR(A, B) A, B 

#if defined(DOXYGEN_PROCESSING) 
# define DOCUMENTED_TYPEDEF_2(x2, y) class y : public PAIR x2 {}; 
#else 
# define DOCUMENTED_TYPEDEF_2(x2, y) typedef PAIR x2 y; 
#endif 

DOCUMENTED_TYPEDEF_2((<R, S>), Bar) 
 
$ gcc -std=c90 -E -Wall -pedantic comma-macro.c 
# 1 "comma-macro.c" 
# 1 "<built-in>" 
# 1 "<command-line>" 
# 1 "comma-macro.c" 
# 11 "comma-macro.c" 
typedef <R, S> Bar; 

Bu arar:

Ayrıca, bu arada, en bir makro sağ tarafta gerekli değildir yararsız COMMA bırakalım . Bununla birlikte, bu yorumda tartışılan taşınabilirlik şartını ihlal edebilir, bunun C++ olduğunu belirtmez. gelecek ziyaretçiler uğruna:

#define PNEUMATIC_COMMA_GUN(A, ...) A, ## __VA_ARGS__ 

#if defined(DOXYGEN_PROCESSING) 
# define DOCUMENTED_TYPEDEF(xv, y) class y : public PNEUMATIC_COMMA_GUN xv {}; 
#else 
# define DOCUMENTED_TYPEDEF(xv, y) typedef PNEUMATIC_COMMA_GUN xv y; 
#endif 

DOCUMENTED_TYPEDEF((<R, S, T, L, N, E>), Bar) 
 
$ gcc -std=c99 -E -Wall -pedantic comma-macro.c 
# 1 "comma-macro.c" 
# 1 "<built-in>" 
# 1 "<command-line>" 
# 1 "comma-macro.c" 
# 9 "comma-macro.c" 
typedef <R, S, T, L, N, E> Bar; 
+0

Bu çok çirkin. Her zaman açgözlü olmayan bir maça güvenebilir miyim? Eğer öyleyse, 'X' ve' Y'yi tersine çevirmeyi düşünüyorum. Zor olan nokta şu şekildedir: iyi tanımlanmış olan, uygulamaya göre tanımlanmış olan. Hemen hemen tüm platformlar için derleyiciler üzerinde çalışmaya ve 1990'lara geri dönmeye ihtiyacım var. Onun özel bir cehennemi. – jww

+0

Önişlemci, parantez içine alınmayan virgüllerde makro bağımsız değişkenleri listeler. (Parantez belirteçleri sayar, böylece dengeler). Köşeli parantez, parantez veya açılı ayraçlar tanınmaz; Virgüllere koruma sağlamazlar. Açgözlülükle pek ilgisi yok. – Kaz

+0

Taşınabilirlik hakkında, yalnızca C90 önişlemci sözdizimini kullandım. – Kaz