2013-03-22 17 views
7

In C++ 98, Uso tipicamente quanto segue per dichiarare una variabile nel tipo di valore di un iteratore:Come dichiarare il valore di un iteratore attraverso decltype

typename std::iterator_traits<Iterator>::value_type value; 

In C++ 11 abbiamo decltype e avevo pensato che il modo più semplice per dedurre il tipo di valore è:

decltype(*iterator) value; 

Purtroppo per la maggior parte iteratori, il tipo di * iteratore è value_type & e non value_type. Qualche idea, senza le classi di modifica del tipo, come massaggiare quanto sopra nel produrre il value_type (e non alcun riferimento)?


Non credo che la domanda sia irragionevole dato che quanto segue è abbastanza robusto ma finisce per creare un'altra variabile.

auto x = *iterator; 
decltype(x) value; 

Si noti inoltre che voglio davvero il tipo dedotta e non solo un esempio esempio se volessi dichiarare un vettore std :: di questi valori.

+0

Il tipo dell'espressione '* iterator' è' std :: :: iterator_traits reference', non 'value_type'. Questo non è necessariamente 'value_type &', e 'decltype' può riportare il tipo di un'espressione in modo diverso rispetto a quanto effettivamente dipende dalla sua categoria di valore. –

+0

Se * solo * vuoi combinare le due righe della tua modifica, l'equivalente sarebbe 'typename std :: decay :: tipo valore;', ma controlla la risposta qui sotto e fai semplicemente 'don' lo faccio :) Sto solo aggiungendo questo come ['std :: decay'] (http://en.cppreference.com/w/cpp/types/decay) non è stato menzionato in questo Q/A prima. –

risposta

15

Continua a utilizzare iterator_traits. decltype(*iterator) potrebbe anche essere una sorta di classe proxy strana per fare cose speciali nell'espressione *iter = something.

Esempio:

#include <iostream> 
#include <iterator> 
#include <typeinfo> 
#include <vector> 

template <typename T> 
void print_type() 
{ 
    std::cout << typeid(T).name() << std::endl; 
} 

template <typename Iterator> 
void test(Iterator iter) 
{ 
    typedef typename 
     std::iterator_traits<Iterator>::value_type iter_traits_value; 

    auto x = *iter; 
    typedef decltype(x) custom_value; 

    print_type<iter_traits_value>(); 
    print_type<custom_value>(); 
} 

int main() 
{ 
    std::vector<int> a; 
    std::vector<bool> b; 

    test(a.begin()); 
    test(b.begin()); 
} 

uscita su MSVC 2012:

int
int
bool
class std::_Vb_reference<struct std::_Wrap_alloc<class std::allocator<unsigned int>>>

Non sono la stessa cosa.

+0

Ma come ho detto nella mia modifica, il seguente funziona: auto x = * iterator; decltype (x) valore; –

+3

@GlenLow: non hai definito "funziona". Vedi la mia modifica alla risposta (aschepler, modifica come preferisci). – GManNickG

+1

+1 per la modifica di @ GManNickG. ; -] – ildjarn

1

Per questo caso d'uso mi piace std :: decay. Typicall Sarei usando

std::vector<int> vec; 
using value_type = typename std::decay< decltype(*begin(vec)) >::type; 
static_assert(std::is_same< int, value_type >::value, "expected int"); 
+0

Grazie per il suggerimento, funziona (e ho imparato qualcosa di nuovo!) Ma non è meno prolisso di 'std :: iterator_traits :: value_type' quando ho già il tipo di Iterator. –

+0

vero. iterator_traits <> sono la strada da percorrere. In realtà sto usando il mio suggerimento di più quando ho, per esempio, un tipo di contenitore sconosciuto. se hai già il tipo iteratore, hai decisamente ragione. –

+0

Si noti che questa espressione potrebbe non funzionare dove il tipo di riferimento dell'iteratore è un proxy perverso, come nella specializzazione 'std :: vector ' riportata sopra. –

Problemi correlati