2013-05-01 10 views
6

Dopo aver visto molti esempi di metaprogrammazione in C++ che consentono di capire le proprietà delle classi (come knowing if a type is a specialization of a template), o sapere se una classe incorpora un dato tipo annidato; ma mi chiedevo se fosse possibile scrivere un test o un tratto che determina l'inverso dell'ultimo - per verificare se un dato Type è nidificato all'interno di un class o struct.C++ - Sapere se un tipo/classe è annidato?

In altre parole, sto cercando l'equivalente del seguente pseudocodice:

template <typename Type> struct is_nested { 
    enum { value = {__some magic__} }; 
}; 

typedef int type1; 
struct Something { typedef int internal_type; }; 
typedef Something::internal_type type2; 

//...later, likely at a different scope 

is_nested<int>::value; // yields false 
is_nested< std::vector<int>::iterator >::value; // yields true 
is_nested<type1>::value; // yields false 
is_nested<type2>::value; // yields true 

So che posso usare per implementare sizeof sì/no test, e presumo Type fa parte di quei test, ma non riesco a capire come inserire una sorta di "qualsiasi tipo valido" nel test in modo da poter formare un'espressione come Anytype::Type.

 
template 
struct is_nested 
{ 
    typedef char yes; 
    typedef struct { char u[2]; } no; 

    // Herein lies the problem 
    ???? static yes test(char [ sizeof(Anytype::Type) ]) ; 
    ???? static no test(...); 


public: 
    enum { value = sizeof(test(0)) == sizeof(char) }; 
}; 

(Si noti che non mi interessa né (posso permettermi di) sapere che cosa tipo sarebbe Type essere annidato in, tutto ciò che conta è se è annidato in qualcosa o meno in altre parole. , questa caratteristica dovrebbe solo dipenderà Type.)

sto cercando una soluzione di C++ sia in C++ 11 o C++ 03, ma nel primo caso avrei accoglierla molto di più se era backportable.

+1

Qual è il problema che questo è destinato a risolvere? –

+0

Sto principalmente teorizzando su come migliorare il mio [adattamento delle enumerazioni typesafe in C++ 03] (http://stackoverflow.com/a/11856721/399580) disabilitando gli operatori relazionali per 'enum's che sono annidati all'interno le strutture; questo è uno dei due approcci che sto studiando per affrontare questo problema. –

risposta

1

quello che stai chiedendo non è possibile, ma non a causa di una limitazione tecnica, piuttosto perché non si può dire sempre se un nome di tipo identifica un tipo nidificato o no - e modelli di lavorare con tipi, non i nomi.

In questo caso, per esempio:

is_nested< std::vector<int>::iterator >::value 

Tu non sai che cosa è iterator. Considerate questa classe my_vector:

template<typename T> 
struct my_vector 
{ 
    typedef T* iterator; 
    // ... 
}; 

Che cosa dovrebbe is_nested<my_vector<int>::iterator>::value rendimento? Probabilmente ti aspetti che il risultato sia true.

Tuttavia, ciò che è nidificato qui è lo alias, non il tipo stesso: il tipo int* non è nidificato. In realtà, mi aspetto che si vorrebbe il seguente cedere false:

is_nested<int*>::value 

Quindi, ecco la stessa is_nested<T> tratto dovrebbe produrre due risultati diversi dato lo stesso tipo di T (int*, in questo caso). Le informazioni basate su cui is_nested<> deve definire value non possono essere recuperate dal tipo T stesso e i modelli funzionano con tipi, non con nomi.

+0

Punto eccellente in materia di pointer-as-iterator e altre situazioni simili che potrebbero sorgere. A quel punto però mi aspetto che il compilatore sia in grado di risolverlo come è noto lo _type_ iteratore; in tal caso, questo tratto, ad esempio, aiuta a determinare se un tipo di contenitore ha memoria contigua (restituisce definitivamente 'false' se il tipo iteratore è un puntatore raw e _likely_ produce' true' altrimenti). –

+0

@LuisMachuca: Non sei sicuro di cosa intendi quando dici "per risolvere * it *". Cosa intendi con "it"? Il tuo tratto 'is_nested <>' otterrebbe un * tipo * in input, che in entrambi i casi è 'int *'. Questo è tutto ciò che 'is_nested <>' conosce. Non è possibile programmare 'is_nested <>' per produrre risultati diversi a seconda degli argomenti del template. –

+0

... Vero, purtroppo. Ciò significa che dovrò scartare questo approccio. –

0

Potrebbe essere possibile verificare se il "tipo canonico" (il tipo di risultato dopo che tutti gli alias sono stati risolti) è annidato utilizzando le funzionalità non standard dei compilatori.

CTTI può ottenere il nome di un tipo in fase di compilazione.Poi trovare : nella stringa:

#include <vector> 
#include "ctti/type_id.hpp" 

constexpr bool has_colon(const ctti::detail::string& s, size_t i) { 
    return i < s.length() ? (s[i] == ':' || has_colon(s, i + 1)) : false; 
} 

template<typename T> 
using is_nested = integral_constant<bool, has_colon(ctti::type_id<T>().name(), 0)>; 

typedef int type1; 
struct Something { typedef int internal_type; }; 
typedef Something::internal_type type2; 

static_assert(!is_nested<int>::value, ""); 
static_assert(is_nested< std::vector<int>::iterator >::value, ""); 
static_assert(!is_nested<type1>::value, ""); 
// static_assert(is_nested<type2>::value, ""); // fail 

Il 4 ° di controllo avrà esito negativo perché type2 è solo int, che non è annidato.

Problemi correlati