2013-02-28 6 views
9

Il seguente codice è tratto da cppreference.com.Const temporaneo dal tipo di modello e perché usare std :: add_const?

#include <iostream> 
#include <type_traits> 

struct foo 
{ 
    void m() { std::cout << "Non-cv\n"; } 
    void m() const { std::cout << "Const\n"; } 
}; 

template <class T> 
void call_m() 
{ 
    T().m(); 
} 

int main() 
{ 
    call_m<foo>(); 
    call_m<std::add_const<foo>::type>(); 
} 

Tuttavia, quando viene compilato con VC++ Nov 2012 CTP, l'uscita è

non-cv

non-cv

piuttosto che l'atteso:

Non cv

Const

Inoltre, qual è la differenza tra le due istruzioni seguenti:

call_m<const foo>();

e

call_m<std::add_const<foo>::type>();

+6

molto probabilmente un bug, funziona come previsto in gcc ... – Nim

risposta

10

Questo sembra essere un bug con MSVC. Usando un'espressione del modulo T() (che è una conversione di tipo esplicita, per quanto riguarda lo standard) si ottiene un valore del tipo specificato.

L'espressione T(), dove T è un semplice-type-specificatore o typename-specificatore per un non-array tipo di oggetto completa o la (possibilmente cv-qualificato) void tipo, crea un prvalue di tipo specificato, che è di valore inizializzato

è solo con tipi non-classe che il const vengono ignorati, a causa di una regola che prvalues ​​non-classe non può avere cv-qualificato tipi:

I valori di classe possono avere tipi qualificati per CV; i valori prerequisiti non di classe hanno sempre tipi cv-non qualificati.

Così l'oggetto temporaneo creato da T() qui dovrebbe essere const e dovrebbe quindi chiamare la funzione const membro.

Per quanto riguarda quando e perché si utilizza std::add_const, possiamo dare un'occhiata al motivo per cui è stato incluso in the proposal. Si afferma che i caratteri di tipo , add_cv, add_pointer e add_reference sono stati rimossi dalla proposta ma successivamente ripristinati dopo i reclami degli utenti di Boost.

La logica è che questi modelli sono tutti utilizzati come funtori del tempo di compilazione che trasformano un tipo in un altro [...]

L'esempio dato è:

// transforms 'tuple<T1,T2,..,Tn>' 
// to 'tuple<T1 const&,T2 const&,..,Tn const&>' 
template< typename Tuple > 
struct tuple_of_refs 
{ 
    // transform tuple element types 
    typedef typename mpl::transform< 
     typename Tuple::elements, 
     add_reference< add_const<_1> > // here! 
    >::type refs; 
    typedef typename tuple_from_sequence<refs>::type type; 
}; 

template< typename Tuple > 
typename tuple_of_refs<Tuple>::type 
tuple_ref(Tuple const& t) 
{ 
    return typename tuple_of_refs<Tuple>::type(t); 
} 

si può pensare mpl::transform come prendere la metaprogrammazione equivalente a tempo di compilazione per un puntatore a funzione come secondo argomento template - add_reference<add_const<...>> viene applicata a ciascuna delle tipologie in Tuple::elements. Questo semplicemente non può essere espresso usando const.

-1

Da quello che ricordo va come segue, è possibile scrivere 3 cons (3 è il numero di scopo) in una dichiarazione di funzione.

prima del tipo di ritorno, dopo la funzione e i suoi parametri, e sui parametri stessi.

const alla fine di una funzione firma significa che la funzione deve assumere l'oggetto di cui è membro è const. In termini pratici significa che chiedi al compilatore di verificare che la funzione membro non cambi in alcun modo i dati dell'oggetto. Significa chiedere al compilatore di verificare che non modifichi direttamente i dati dei membri, e non chiama alcuna funzione che di per sé non garantisce che non cambierà l'oggetto.

prima del tipo restituito indica che la funzione che la funzione deve restituire deve essere una const.

parametro const indica che il parametro non può essere modificato.

quindi la differenza qui è che la prima chiamata non è una const, quindi va al "non-cv", la seconda è una const e quindi va a "const".

quello che penso del motivo per cui VC++ va alla stessa funzione entrambe le volte è che call_m richiede esplicitamente T(). M() pensando che non dovrebbe andare a quello const.