2013-05-01 18 views
6

Po obejrzeniu wielu przykładów metaprogramowania w C++, które pozwalają na wykreślenie właściwości klas (takich jak knowing if a type is a specialization of a template) lub ustalenie, czy klasa zawiera dany typ zagnieżdżony; ale zastanawiałem się, czy można napisać test lub cechę, która określa odwrotność ostatniego - sprawdzić, czy dany Type jest zagnieżdżony w obrębie class lub struct.C++ - Wiesz, czy typ/klasa jest zagnieżdżona?

Innymi słowy, szukam odpowiednika następującym Pseudokod:

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 

wiem, że mogę używać sizeof wdrożyć tak/nie testy, a przypuszczam Type jest częścią tych badań, ale nie mogę wymyślić, jak podłączyć jakiś rodzaj "dowolnego realnego typu" do testu tak, że mogę utworzyć wyrażenie takie jak 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) }; 
}; 

(Zauważ, że nie obchodzi mnie ani (można sobie pozwolić) wie co typ będzie Type być zagnieżdżone w; wszystko to ma znaczenie to, czy jest zagnieżdżony w coś czy nie Innymi słowy. ta cecha powinna tylko zależą Type.)

szukam dla C++ czy to rozwiązanie w C++ lub C++ 11 03, ale w pierwszym przypadku chciałbym powitać go znacznie więcej, jeśli go był zwrotny.

+1

Na czym polega problem, który ma rozwiązać? –

+0

Jestem głównie teoretyzowania, w jaki sposób poprawić moje [adaptacja typesafe enums w C++ 03] (http://stackoverflow.com/a/11856721/399580) przez wyłączenie operatorów relacyjnych dla 'enum's, które są zagnieżdżone wewnątrz struktury; jest to jedno z dwóch podejść, które studiuję, aby rozwiązać ten problem. –

Odpowiedz

1

co prosicie nie jest możliwe, ale nie ze względu na ograniczenia techniczne, a ponieważ nie zawsze można powiedzieć, czy nazwa typu identyfikuje typ zagnieżdżony lub nie - i szablony pracować z typów, a nie nazwy.

W tym przypadku, na przykład:

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

Nie wiem co iterator jest. Rozważmy tę klasę my_vector:

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

Co powinien is_nested<my_vector<int>::iterator>::value wydajność? Prawdopodobnie oczekuje się, że wynik będzie true.

Jednak to, co jest zagnieżdżony jest tu alias, a nie sam typ: typ int* nie jest zagnieżdżona. W rzeczywistości, spodziewam się, że chcesz dodaje uzyskując false:

is_nested<int*>::value 

Więc tym samym is_nested<T> cechy powinien otrzymać dwa różne wyniki, biorąc pod uwagę sam typ T (int*, w tym przypadku). Informacji, na podstawie których należy zdefiniować value, nie można pobrać z samego typu T - a szablony działają z typami, a nie nazwami.

+0

Doskonały punkt na temat wskaźnika-jako-iteratora i innych podobnych sytuacji, które mogą się pojawić. W tym momencie jednak oczekiwałbym, że kompilator będzie w stanie go rozwiązać, gdy znany jest iterator _type_; w takim przypadku ta właściwość pomogłaby na przykład w ustaleniu, czy typ kontenera ma ciągłe miejsce przechowywania (ostatecznie powodowałby "fałsz", gdyby typ iteratora był wskaźnikiem nieprzetworzonym, a "prawdopodobnie" powodowałoby "true" w przeciwnym razie). –

+0

@LuisMachuca: Nie wiesz, co masz na myśli mówiąc "rozwiązać * to *". Co masz na myśli przez "to"? Twoja własność 'is_nested <>' otrzymywałaby * typ * na wejściu, który w obu przypadkach jest 'int *'. To wszystko "is_nested <>" wie. Nie ma możliwości zaprogramowania 'is_nested <> w celu wygenerowania różnych wyników z tymi samymi argumentami szablonu. –

+0

... To prawda, niestety. Oznacza to, że będę musiał odrzucić to podejście. –

0

Możliwe jest sprawdzenie, czy "typ kanoniczny" (typ wyniku po rozwiązaniu wszystkich aliasów) jest zagnieżdżony przy użyciu niestandardowych funkcji kompilatorów.

CTTI może uzyskać nazwę typu w czasie kompilacji.Następnie znajdź : w ciągu:

#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 

4th test zawiedzie bo type2 tylko int, które nie są zagnieżdżone.

Powiązane problemy