]>
Commit | Line | Data |
---|---|---|
1 | ///////////////////////////////////////////////////////////////////////////// | |
2 | // Name: wx/xtitypes.h | |
3 | // Purpose: enum, set, basic types support | |
4 | // Author: Stefan Csomor | |
5 | // Modified by: Francesco Montorsi | |
6 | // Created: 27/07/03 | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) 1997 Julian Smart | |
9 | // (c) 2003 Stefan Csomor | |
10 | // Licence: wxWindows licence | |
11 | ///////////////////////////////////////////////////////////////////////////// | |
12 | ||
13 | #ifndef _XTITYPES_H_ | |
14 | #define _XTITYPES_H_ | |
15 | ||
16 | #include "wx/defs.h" | |
17 | ||
18 | #if wxUSE_EXTENDED_RTTI | |
19 | ||
20 | #include "wx/string.h" | |
21 | #include "wx/hashmap.h" | |
22 | #include "wx/arrstr.h" | |
23 | #include "wx/flags.h" | |
24 | #include "wx/intl.h" | |
25 | #include "wx/log.h" | |
26 | #include <typeinfo> | |
27 | ||
28 | class WXDLLIMPEXP_BASE wxClassInfo; | |
29 | ||
30 | // ---------------------------------------------------------------------------- | |
31 | // Enum Support | |
32 | // | |
33 | // In the header files XTI requires no change from pure c++ code, however in the | |
34 | // implementation, an enum needs to be enumerated eg: | |
35 | // | |
36 | // wxBEGIN_ENUM( wxFlavor ) | |
37 | // wxENUM_MEMBER( Vanilla ) | |
38 | // wxENUM_MEMBER( Chocolate ) | |
39 | // wxENUM_MEMBER( Strawberry ) | |
40 | // wxEND_ENUM( wxFlavor ) | |
41 | // ---------------------------------------------------------------------------- | |
42 | ||
43 | struct WXDLLIMPEXP_BASE wxEnumMemberData | |
44 | { | |
45 | const wxChar* m_name; | |
46 | int m_value; | |
47 | }; | |
48 | ||
49 | class WXDLLIMPEXP_BASE wxEnumData | |
50 | { | |
51 | public: | |
52 | wxEnumData( wxEnumMemberData* data ); | |
53 | ||
54 | // returns true if the member has been found and sets the int value | |
55 | // pointed to accordingly (if ptr != null ) | |
56 | // if not found returns false, value left unchanged | |
57 | bool HasEnumMemberValue( const wxChar *name, int *value = NULL ) const; | |
58 | ||
59 | // returns the value of the member, if not found in debug mode an | |
60 | // assert is issued, in release 0 is returned | |
61 | int GetEnumMemberValue(const wxChar *name ) const; | |
62 | ||
63 | // returns the name of the enum member having the passed in value | |
64 | // returns an emtpy string if not found | |
65 | const wxChar *GetEnumMemberName(int value) const; | |
66 | ||
67 | // returns the number of members in this enum | |
68 | int GetEnumCount() const { return m_count; } | |
69 | ||
70 | // returns the value of the nth member | |
71 | int GetEnumMemberValueByIndex( int n ) const; | |
72 | ||
73 | // returns the value of the nth member | |
74 | const wxChar *GetEnumMemberNameByIndex( int n ) const; | |
75 | ||
76 | private: | |
77 | wxEnumMemberData *m_members; | |
78 | int m_count; | |
79 | }; | |
80 | ||
81 | #define wxBEGIN_ENUM( e ) \ | |
82 | wxEnumMemberData s_enumDataMembers##e[] = { | |
83 | ||
84 | #define wxENUM_MEMBER( v ) { wxT(#v), v }, | |
85 | ||
86 | #define wxEND_ENUM( e ) \ | |
87 | { NULL, 0 } }; \ | |
88 | wxEnumData s_enumData##e( s_enumDataMembers##e ); \ | |
89 | wxEnumData *wxGetEnumData(e) { return &s_enumData##e; } \ | |
90 | template<> void wxStringReadValue(const wxString& s, e &data ) \ | |
91 | { data = (e) s_enumData##e.GetEnumMemberValue(s.c_str()); } \ | |
92 | template<> void wxStringWriteValue(wxString &s, const e &data ) \ | |
93 | { s = s_enumData##e.GetEnumMemberName((int)data); } \ | |
94 | void FromLong##e( long data, wxAny& result ) \ | |
95 | { result = wxAny((e)data); } \ | |
96 | void ToLong##e( const wxAny& data, long &result ) \ | |
97 | { result = (long) (data).As(static_cast<e*>(NULL)); } \ | |
98 | \ | |
99 | wxTO_STRING_IMP( e ) \ | |
100 | wxFROM_STRING_IMP( e ) \ | |
101 | wxEnumTypeInfo s_typeInfo##e(wxT_ENUM, &s_enumData##e, \ | |
102 | &wxTO_STRING( e ), &wxFROM_STRING( e ), &ToLong##e, \ | |
103 | &FromLong##e, typeid(e).name() ); | |
104 | ||
105 | ||
106 | // ---------------------------------------------------------------------------- | |
107 | // Set Support | |
108 | // | |
109 | // in the header : | |
110 | // | |
111 | // enum wxFlavor | |
112 | // { | |
113 | // Vanilla, | |
114 | // Chocolate, | |
115 | // Strawberry, | |
116 | // }; | |
117 | // | |
118 | // typedef wxBitset<wxFlavor> wxCoupe; | |
119 | // | |
120 | // in the implementation file : | |
121 | // | |
122 | // wxBEGIN_ENUM( wxFlavor ) | |
123 | // wxENUM_MEMBER( Vanilla ) | |
124 | // wxENUM_MEMBER( Chocolate ) | |
125 | // wxENUM_MEMBER( Strawberry ) | |
126 | // wxEND_ENUM( wxFlavor ) | |
127 | // | |
128 | // wxIMPLEMENT_SET_STREAMING( wxCoupe, wxFlavor ) | |
129 | // | |
130 | // implementation note: no partial specialization for streaming, but a delegation | |
131 | // to a different class | |
132 | // | |
133 | // ---------------------------------------------------------------------------- | |
134 | ||
135 | void WXDLLIMPEXP_BASE wxSetStringToArray( const wxString &s, wxArrayString &array ); | |
136 | ||
137 | template<typename e> | |
138 | void wxSetFromString(const wxString &s, wxBitset<e> &data ) | |
139 | { | |
140 | wxEnumData* edata = wxGetEnumData((e) 0); | |
141 | data.reset(); | |
142 | ||
143 | wxArrayString array; | |
144 | wxSetStringToArray( s, array ); | |
145 | wxString flag; | |
146 | for ( int i = 0; i < array.Count(); ++i ) | |
147 | { | |
148 | flag = array[i]; | |
149 | int ivalue; | |
150 | if ( edata->HasEnumMemberValue( flag.c_str(), &ivalue ) ) | |
151 | { | |
152 | data.set( (e) ivalue ); | |
153 | } | |
154 | } | |
155 | } | |
156 | ||
157 | template<typename e> | |
158 | void wxSetToString( wxString &s, const wxBitset<e> &data ) | |
159 | { | |
160 | wxEnumData* edata = wxGetEnumData((e) 0); | |
161 | int count = edata->GetEnumCount(); | |
162 | int i; | |
163 | s.Clear(); | |
164 | for ( i = 0; i < count; i++ ) | |
165 | { | |
166 | e value = (e) edata->GetEnumMemberValueByIndex(i); | |
167 | if ( data.test( value ) ) | |
168 | { | |
169 | // this could also be done by the templated calls | |
170 | if ( !s.empty() ) | |
171 | s += wxT("|"); | |
172 | s += edata->GetEnumMemberNameByIndex(i); | |
173 | } | |
174 | } | |
175 | } | |
176 | ||
177 | #define wxIMPLEMENT_SET_STREAMING(SetName,e) \ | |
178 | template<> void wxStringReadValue(const wxString &s, wxBitset<e> &data ) \ | |
179 | { wxSetFromString( s, data ); } \ | |
180 | template<> void wxStringWriteValue( wxString &s, const wxBitset<e> &data ) \ | |
181 | { wxSetToString( s, data ); } \ | |
182 | void FromLong##SetName( long data, wxAny& result ) \ | |
183 | { result = wxAny(SetName((unsigned long)data)); } \ | |
184 | void ToLong##SetName( const wxAny& data, long &result ) \ | |
185 | { result = (long) (data).As(static_cast<SetName*>(NULL)).to_ulong(); } \ | |
186 | wxTO_STRING_IMP( SetName ) \ | |
187 | wxFROM_STRING_IMP( SetName ) \ | |
188 | wxEnumTypeInfo s_typeInfo##SetName(wxT_SET, &s_enumData##e, \ | |
189 | &wxTO_STRING( SetName ), &wxFROM_STRING( SetName ), \ | |
190 | &ToLong##SetName, &FromLong##SetName, typeid(SetName).name() ); | |
191 | ||
192 | template<typename e> | |
193 | void wxFlagsFromString(const wxString &s, e &data ) | |
194 | { | |
195 | wxEnumData* edata = wxGetEnumData((e*) 0); | |
196 | data.m_data = 0; | |
197 | ||
198 | wxArrayString array; | |
199 | wxSetStringToArray( s, array ); | |
200 | wxString flag; | |
201 | for ( size_t i = 0; i < array.Count(); ++i ) | |
202 | { | |
203 | flag = array[i]; | |
204 | int ivalue; | |
205 | if ( edata->HasEnumMemberValue( flag.c_str(), &ivalue ) ) | |
206 | { | |
207 | data.m_data |= ivalue; | |
208 | } | |
209 | } | |
210 | } | |
211 | ||
212 | template<typename e> | |
213 | void wxFlagsToString( wxString &s, const e& data ) | |
214 | { | |
215 | wxEnumData* edata = wxGetEnumData((e*) 0); | |
216 | int count = edata->GetEnumCount(); | |
217 | int i; | |
218 | s.Clear(); | |
219 | long dataValue = data.m_data; | |
220 | for ( i = 0; i < count; i++ ) | |
221 | { | |
222 | int value = edata->GetEnumMemberValueByIndex(i); | |
223 | // make this to allow for multi-bit constants to work | |
224 | if ( value && ( dataValue & value ) == value ) | |
225 | { | |
226 | // clear the flags we just set | |
227 | dataValue &= ~value; | |
228 | // this could also be done by the templated calls | |
229 | if ( !s.empty() ) | |
230 | s +=wxT("|"); | |
231 | s += edata->GetEnumMemberNameByIndex(i); | |
232 | } | |
233 | } | |
234 | } | |
235 | ||
236 | #define wxBEGIN_FLAGS( e ) \ | |
237 | wxEnumMemberData s_enumDataMembers##e[] = { | |
238 | ||
239 | #define wxFLAGS_MEMBER( v ) { wxT(#v), v }, | |
240 | ||
241 | #define wxEND_FLAGS( e ) \ | |
242 | { NULL, 0 } }; \ | |
243 | wxEnumData s_enumData##e( s_enumDataMembers##e ); \ | |
244 | wxEnumData *wxGetEnumData(e*) { return &s_enumData##e; } \ | |
245 | template<> void wxStringReadValue(const wxString &s, e &data ) \ | |
246 | { wxFlagsFromString<e>( s, data ); } \ | |
247 | template<> void wxStringWriteValue( wxString &s, const e& data ) \ | |
248 | { wxFlagsToString<e>( s, data ); } \ | |
249 | void FromLong##e( long data, wxAny& result ) \ | |
250 | { result = wxAny(e(data)); } \ | |
251 | void ToLong##e( const wxAny& data, long &result ) \ | |
252 | { result = (long) (data).As(static_cast<e*>(NULL)).m_data; } \ | |
253 | wxTO_STRING_IMP( e ) \ | |
254 | wxFROM_STRING_IMP( e ) \ | |
255 | wxEnumTypeInfo s_typeInfo##e(wxT_SET, &s_enumData##e, \ | |
256 | &wxTO_STRING( e ), &wxFROM_STRING( e ), &ToLong##e, \ | |
257 | &FromLong##e, typeid(e).name() ); | |
258 | ||
259 | // ---------------------------------------------------------------------------- | |
260 | // Type Information | |
261 | // ---------------------------------------------------------------------------- | |
262 | ||
263 | // All data exposed by the RTTI is characterized using the following classes. | |
264 | // The first characterization is done by wxTypeKind. All enums up to and including | |
265 | // wxT_CUSTOM represent so called simple types. These cannot be divided any further. | |
266 | // They can be converted to and from wxStrings, that's all. | |
267 | // Other wxTypeKinds can instead be splitted recursively into smaller parts until | |
268 | // the simple types are reached. | |
269 | ||
270 | enum wxTypeKind | |
271 | { | |
272 | wxT_VOID = 0, // unknown type | |
273 | wxT_BOOL, | |
274 | wxT_CHAR, | |
275 | wxT_UCHAR, | |
276 | wxT_INT, | |
277 | wxT_UINT, | |
278 | wxT_LONG, | |
279 | wxT_ULONG, | |
280 | wxT_LONGLONG, | |
281 | wxT_ULONGLONG, | |
282 | wxT_FLOAT, | |
283 | wxT_DOUBLE, | |
284 | wxT_STRING, // must be wxString | |
285 | wxT_SET, // must be wxBitset<> template | |
286 | wxT_ENUM, | |
287 | wxT_CUSTOM, // user defined type (e.g. wxPoint) | |
288 | ||
289 | wxT_LAST_SIMPLE_TYPE_KIND = wxT_CUSTOM, | |
290 | ||
291 | wxT_OBJECT_PTR, // object reference | |
292 | wxT_OBJECT, // embedded object | |
293 | wxT_COLLECTION, // collection | |
294 | ||
295 | wxT_DELEGATE, // for connecting against an event source | |
296 | ||
297 | wxT_LAST_TYPE_KIND = wxT_DELEGATE // sentinel for bad data, asserts, debugging | |
298 | }; | |
299 | ||
300 | class WXDLLIMPEXP_BASE wxAny; | |
301 | class WXDLLIMPEXP_BASE wxTypeInfo; | |
302 | ||
303 | WX_DECLARE_STRING_HASH_MAP_WITH_DECL( wxTypeInfo*, wxTypeInfoMap, class WXDLLIMPEXP_BASE ); | |
304 | ||
305 | class WXDLLIMPEXP_BASE wxTypeInfo | |
306 | { | |
307 | public: | |
308 | typedef void (*wxVariant2StringFnc)( const wxAny& data, wxString &result ); | |
309 | typedef void (*wxString2VariantFnc)( const wxString& data, wxAny &result ); | |
310 | ||
311 | wxTypeInfo(wxTypeKind kind, | |
312 | wxVariant2StringFnc to = NULL, wxString2VariantFnc from = NULL, | |
313 | const wxString &name = wxEmptyString): | |
314 | m_toString(to), m_fromString(from), m_kind(kind), m_name(name) | |
315 | { | |
316 | Register(); | |
317 | } | |
318 | #if 0 // wxUSE_UNICODE | |
319 | wxTypeInfo(wxTypeKind kind, | |
320 | wxVariant2StringFnc to, wxString2VariantFnc from, | |
321 | const char *name): | |
322 | m_toString(to), m_fromString(from), m_kind(kind), | |
323 | m_name(wxString::FromAscii(name)) | |
324 | { | |
325 | Register(); | |
326 | } | |
327 | #endif | |
328 | ||
329 | virtual ~wxTypeInfo() | |
330 | { | |
331 | Unregister(); | |
332 | } | |
333 | ||
334 | // return the kind of this type (wxT_... constants) | |
335 | wxTypeKind GetKind() const { return m_kind; } | |
336 | ||
337 | // returns the unique name of this type | |
338 | const wxString& GetTypeName() const { return m_name; } | |
339 | ||
340 | // is this type a delegate type | |
341 | bool IsDelegateType() const { return m_kind == wxT_DELEGATE; } | |
342 | ||
343 | // is this type a custom type | |
344 | bool IsCustomType() const { return m_kind == wxT_CUSTOM; } | |
345 | ||
346 | // is this type an object type | |
347 | bool IsObjectType() const { return m_kind == wxT_OBJECT || m_kind == wxT_OBJECT_PTR; } | |
348 | ||
349 | // can the content of this type be converted to and from strings ? | |
350 | bool HasStringConverters() const { return m_toString != NULL && m_fromString != NULL; } | |
351 | ||
352 | // convert a wxAny holding data of this type into a string | |
353 | void ConvertToString( const wxAny& data, wxString &result ) const | |
354 | { | |
355 | if ( m_toString ) | |
356 | (*m_toString)( data, result ); | |
357 | else | |
358 | wxLogError( wxGetTranslation(wxT("String conversions not supported")) ); | |
359 | } | |
360 | ||
361 | // convert a string into a wxAny holding the corresponding data in this type | |
362 | void ConvertFromString( const wxString& data, wxAny &result ) const | |
363 | { | |
364 | if( m_fromString ) | |
365 | (*m_fromString)( data, result ); | |
366 | else | |
367 | wxLogError( wxGetTranslation(wxT("String conversions not supported")) ); | |
368 | } | |
369 | ||
370 | // statics: | |
371 | ||
372 | // looks for the corresponding type, will return NULL if not found | |
373 | static wxTypeInfo *FindType( const wxString& typeName ); | |
374 | private: | |
375 | void Register(); | |
376 | void Unregister(); | |
377 | ||
378 | wxVariant2StringFnc m_toString; | |
379 | wxString2VariantFnc m_fromString; | |
380 | ||
381 | wxTypeKind m_kind; | |
382 | wxString m_name; | |
383 | ||
384 | // the static list of all types we know about | |
385 | static wxTypeInfoMap* ms_typeTable; | |
386 | }; | |
387 | ||
388 | class WXDLLIMPEXP_BASE wxBuiltInTypeInfo : public wxTypeInfo | |
389 | { | |
390 | public: | |
391 | wxBuiltInTypeInfo( wxTypeKind kind, wxVariant2StringFnc to = NULL, | |
392 | wxString2VariantFnc from = NULL, | |
393 | const wxString &name = wxEmptyString ) : | |
394 | wxTypeInfo( kind, to, from, name ) | |
395 | { wxASSERT_MSG( GetKind() < wxT_SET, wxT("Illegal Kind for Base Type") ); } | |
396 | }; | |
397 | ||
398 | class WXDLLIMPEXP_BASE wxCustomTypeInfo : public wxTypeInfo | |
399 | { | |
400 | public: | |
401 | wxCustomTypeInfo( const wxString &name, wxVariant2StringFnc to, | |
402 | wxString2VariantFnc from ) : | |
403 | wxTypeInfo( wxT_CUSTOM, to, from, name ) | |
404 | {} | |
405 | }; | |
406 | ||
407 | class WXDLLIMPEXP_BASE wxEnumTypeInfo : public wxTypeInfo | |
408 | { | |
409 | public: | |
410 | typedef void (*converterToLong_t)( const wxAny& data, long &result ); | |
411 | typedef void (*converterFromLong_t)( long data, wxAny &result ); | |
412 | ||
413 | wxEnumTypeInfo( wxTypeKind kind, wxEnumData* enumInfo, wxVariant2StringFnc to, | |
414 | wxString2VariantFnc from, converterToLong_t toLong, | |
415 | converterFromLong_t fromLong, const wxString &name ) : | |
416 | wxTypeInfo( kind, to, from, name ), m_toLong( toLong ), m_fromLong( fromLong ) | |
417 | { | |
418 | wxASSERT_MSG( kind == wxT_ENUM || kind == wxT_SET, | |
419 | wxT("Illegal Kind for Enum Type")); | |
420 | m_enumInfo = enumInfo; | |
421 | } | |
422 | ||
423 | const wxEnumData* GetEnumData() const { return m_enumInfo; } | |
424 | ||
425 | // convert a wxAny holding data of this type into a long | |
426 | void ConvertToLong( const wxAny& data, long &result ) const | |
427 | { | |
428 | if( m_toLong ) | |
429 | (*m_toLong)( data, result ); | |
430 | else | |
431 | wxLogError( wxGetTranslation(wxT("Long Conversions not supported")) ); | |
432 | } | |
433 | ||
434 | // convert a long into a wxAny holding the corresponding data in this type | |
435 | void ConvertFromLong( long data, wxAny &result ) const | |
436 | { | |
437 | if( m_fromLong ) | |
438 | (*m_fromLong)( data, result ); | |
439 | else | |
440 | wxLogError( wxGetTranslation(wxT("Long Conversions not supported")) ); | |
441 | } | |
442 | ||
443 | private: | |
444 | converterToLong_t m_toLong; | |
445 | converterFromLong_t m_fromLong; | |
446 | ||
447 | wxEnumData *m_enumInfo; // Kind == wxT_ENUM or Kind == wxT_SET | |
448 | }; | |
449 | ||
450 | class WXDLLIMPEXP_BASE wxClassTypeInfo : public wxTypeInfo | |
451 | { | |
452 | public: | |
453 | wxClassTypeInfo( wxTypeKind kind, wxClassInfo* classInfo, | |
454 | wxVariant2StringFnc to = NULL, wxString2VariantFnc from = NULL, | |
455 | const wxString &name = wxEmptyString); | |
456 | ||
457 | const wxClassInfo *GetClassInfo() const { return m_classInfo; } | |
458 | ||
459 | private: | |
460 | wxClassInfo *m_classInfo; // Kind == wxT_OBJECT - could be NULL | |
461 | }; | |
462 | ||
463 | class WXDLLIMPEXP_BASE wxCollectionTypeInfo : public wxTypeInfo | |
464 | { | |
465 | public: | |
466 | wxCollectionTypeInfo( const wxString &elementName, wxVariant2StringFnc to, | |
467 | wxString2VariantFnc from , const wxString &name) : | |
468 | wxTypeInfo( wxT_COLLECTION, to, from, name ) | |
469 | { m_elementTypeName = elementName; m_elementType = NULL; } | |
470 | ||
471 | const wxTypeInfo* GetElementType() const | |
472 | { | |
473 | if ( m_elementType == NULL ) | |
474 | m_elementType = wxTypeInfo::FindType( m_elementTypeName ); | |
475 | return m_elementType; | |
476 | } | |
477 | ||
478 | private: | |
479 | mutable wxTypeInfo * m_elementType; | |
480 | wxString m_elementTypeName; | |
481 | }; | |
482 | ||
483 | class WXDLLIMPEXP_BASE wxEventSourceTypeInfo : public wxTypeInfo | |
484 | { | |
485 | public: | |
486 | wxEventSourceTypeInfo( int eventType, wxClassInfo* eventClass, | |
487 | wxVariant2StringFnc to = NULL, | |
488 | wxString2VariantFnc from = NULL ); | |
489 | wxEventSourceTypeInfo( int eventType, int lastEventType, wxClassInfo* eventClass, | |
490 | wxVariant2StringFnc to = NULL, wxString2VariantFnc from = NULL ); | |
491 | ||
492 | int GetEventType() const { return m_eventType; } | |
493 | int GetLastEventType() const { return m_lastEventType; } | |
494 | const wxClassInfo* GetEventClass() const { return m_eventClass; } | |
495 | ||
496 | private: | |
497 | const wxClassInfo *m_eventClass; // (extended will merge into classinfo) | |
498 | int m_eventType; | |
499 | int m_lastEventType; | |
500 | }; | |
501 | ||
502 | template<typename T> const wxTypeInfo* wxGetTypeInfo( T * ) | |
503 | { return wxTypeInfo::FindType(typeid(T).name()); } | |
504 | ||
505 | // this macro is for usage with custom, non-object derived classes and structs, | |
506 | // wxPoint is such a custom type | |
507 | ||
508 | #if wxUSE_FUNC_TEMPLATE_POINTER | |
509 | #define wxCUSTOM_TYPE_INFO( e, toString, fromString ) \ | |
510 | wxCustomTypeInfo s_typeInfo##e(typeid(e).name(), &toString, &fromString); | |
511 | #else | |
512 | #define wxCUSTOM_TYPE_INFO( e, toString, fromString ) \ | |
513 | void ToString##e( const wxAny& data, wxString &result ) \ | |
514 | { toString(data, result); } \ | |
515 | void FromString##e( const wxString& data, wxAny &result ) \ | |
516 | { fromString(data, result); } \ | |
517 | wxCustomTypeInfo s_typeInfo##e(typeid(e).name(), \ | |
518 | &ToString##e, &FromString##e); | |
519 | #endif | |
520 | ||
521 | #define wxCOLLECTION_TYPE_INFO( element, collection ) \ | |
522 | wxCollectionTypeInfo s_typeInfo##collection( typeid(element).name(), \ | |
523 | NULL, NULL, typeid(collection).name() ); | |
524 | ||
525 | // sometimes a compiler invents specializations that are nowhere called, | |
526 | // use this macro to satisfy the refs, currently we don't have to play | |
527 | // tricks, but if we will have to according to the compiler, we will use | |
528 | // that macro for that | |
529 | ||
530 | #define wxILLEGAL_TYPE_SPECIALIZATION( a ) | |
531 | ||
532 | #endif // wxUSE_EXTENDED_RTTI | |
533 | #endif // _XTITYPES_H_ |