2010-07-05 16 views
5

Chcę zaimplementować is_pointer. Chcę coś takiego:jak zaimplementować is_pointer?

template <typename T > 
bool is_pointer(T t) 
{ 
    // implementation 
} // return true or false 

int a; 
char *c; 
SomeClass sc; 
someAnotherClass *sac; 

is_pointer(a); // return false 

is_pointer(c); // return true 

is_pointer(sc); // return false 

is_pointer(sac); // return true 

Jak mogę to wdrożyć? Dzięki

Odpowiedz

18
template <typename T> 
struct is_pointer_type 
{ 
    enum { value = false }; 
}; 

template <typename T> 
struct is_pointer_type<T*> 
{ 
    enum { value = true }; 
}; 

template <typename T> 
bool is_pointer(const T&) 
{ 
    return is_pointer_type<T>::value; 
} 

Johannes zauważył:

To jest rzeczywiście brakuje specjalizacje dla const T * T * T * lotny i const lotny myślę.

Rozwiązanie:

template <typename T> 
struct remove_const 
{ 
    typedef T type; 
}; 

template <typename T> 
struct remove_const<const T> 
{ 
    typedef T type; 
}; 

template <typename T> 
struct remove_volatile 
{ 
    typedef T type; 
}; 

template <typename T> 
struct remove_volatile<volatile T> 
{ 
    typedef T type; 
}; 

template <typename T> 
struct remove_cv : remove_const<typename remove_volatile<T>::type> {}; 

template <typename T> 
struct is_unqualified_pointer 
{ 
    enum { value = false }; 
}; 

template <typename T> 
struct is_unqualified_pointer<T*> 
{ 
    enum { value = true }; 
}; 

template <typename T> 
struct is_pointer_type : is_unqualified_pointer<typename remove_cv<T>::type> {}; 

template <typename T> 
bool is_pointer(const T&) 
{ 
    return is_pointer_type<T>::value; 
} 

... ale oczywiście to jest po prostu wymyślania koła std::type_traits, bardziej lub mniej :)

+0

Czy jest jakiś powód, aby używać tego rozwiązania zamiast tego, które podaje Thomas? – Job

+1

@Job Działa dla typów niekodowanych :) – fredoverflow

+0

Tak, oczywiście :) Miałem na myśli odpowiedź Thomasa, ale jako "const T &" jako parametr. – Job

10

From Dr. Dobbs.

template <typename T> 
struct is_pointer 
{ static const bool value = false; }; 

template <typename T> 
struct is_pointer<T*> 
{ static const bool value = true; }; 

Nie można zrobić dokładnie co chcesz zrobić. Będziesz musiał użyć tego, jak:

is_pointer<int*>::value 

Nie można tego ustalić w czasie wykonywania.

+2

Cóż, tak naprawdę, jeśli możesz mieć go w kompilacji, możesz mieć go w czasie wykonywania. Odwrotna sytuacja jest zwykle trudniejsza. W każdym razie to jest rozwiązanie, do którego dążyłbym ... lub po prostu użycie biblioteki Boost Type Traits. –

+0

Piotrze to wygląda dobrze, ale proszę spojrzeć na mój przykład, chcę przekazać zmienną podobną do tej: int ival; is_pointer (ival); zamiast is_pointer lub is_pointer (int) –

+0

Każdy zasób daje tę implementację, ale nie rozumiem, dlaczego specjalizacja częściowa została wybrana dla 'int *' lub innych typów wskaźników, zamiast pierwszego szablonu podstawowego? Jaki jest mechanizm? Czy dzieje się coś w rodzaju odliczenia? Myślałem, że jest to możliwe tylko w szablonach funkcyjnych. – meguli

8
template <typename T> 
bool is_pointer(T const &t) // edited: was "T t"; see the comments 
{ 
    return false; 
} 

template <typename T> 
bool is_pointer(T *t) 
{ 
    return true; 
} 

Możesz w to nie wierzyć, ale działa. Powodem jest to, że wybrana zostanie najbardziej szczegółowa implementacja szablonu, która przyjmuje typ wskaźnika.

+2

To nie zadziała dla typów bez kopii. – fredoverflow

+0

To prawda, nie jest to najlepsze rozwiązanie. Właśnie dlatego podniosłem na duchu Petera Alexandra i ciebie po tym zamieszczeniu :) – Thomas

+0

+1, ponieważ właśnie tego chciał PO. Pierwowzorem pierwszej funkcji powinno być 'bool is_pointer (T &)', ponieważ FredOverflow podał w swoim komentarzu. – Job

-2

Można użyć operatora "typeid" zdefiniowane w typeinfo.h dla tego. Sprawdź ten link: http://en.wikipedia.org/wiki/Typeid

Operator typu id da obiekt klasy std :: typ_info, który ma funkcję zwracającą nazwę *. Po otrzymaniu typu w postaci ciągu można łatwo zidentyfikować wskaźnik.

Mam nadzieję, że to pomaga.

Romil.

+1

-1, nie działa. Zestaw std :: typ_info :: nazwa dla wskaźników może przecinać zbiór std :: type_info :: name dla non-pointers. W szczególności wszystkie nazwy mogą być prawnie "" ". – MSalters

+0

To. Ciąg zwracany przez .name jest zdefiniowany w całości przez implementację. – Puppy