2013-02-28 3 views
9

Der folgende Code stammt aus cppreference.com.Const vorübergehend vom Schablonentyp und warum std :: add_const verwenden?

#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>(); 
} 

Wenn jedoch mit VC++ November 2012 CTP erstellt, ist der Ausgang

Non-cv

Non-cv

statt der erwarteten:

Nicht-cv

Konst

Außerdem, was ist der Unterschied zwischen den beiden folgenden Anweisungen:

call_m<const foo>();

und

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

+6

höchstwahrscheinlich ein Fehler, funktioniert wie erwartet in gcc ... – Nim

Antwort

10

Dies scheint ein Fehler mit MSVC zu sein. Mit einem Ausdruck des Formulars T() (was eine explizite Typumwandlung ist, was den Standard betrifft) ergibt sich ein prvalue des angegebenen Typs.

Der Ausdruck T(), wo T ist ein simple-Typ-Spezifizierer oder typename-Spezifizierer für einen nicht-Array vollständigen Objekttyp oder die (möglicherweise cv-qualifiziert) void Typen, schafft eine prvalue von der angegebene Typ, der

Wert initialisiert ist

Es ist nur mit nicht-Klasse-Typen, die die const ignoriert werden würde, aufgrund einer Regel, die nicht-Klasse prvalues ​​nicht cv-qualifizierte Typen haben:

Klasse prvalues ​​kann cv-qualifizierte Typen haben; Nicht-Klasse Prvalues ​​haben immer cv-unqualifizierte Typen.

So ist die temporäre Objekt erstellt von T() hier sollte const sein und sollte deshalb rufen Sie die const Memberfunktion.

Wie für wann und warum Sie std::add_const verwenden würden, können wir einen Blick auf den Grund werfen, warum es in the proposal enthalten war. Es heißt, dass die Merkmale des Typs add_const, , add_pointer und add_reference aus dem Vorschlag entfernt wurden, aber dann nach Beschwerden von Nutzern von Boost wieder eingesetzt wurden.

Das Grundprinzip ist, dass diese Vorlagen alle als Kompilierzeit Funktoren verwendet werden, die einen Typ in einen anderen umwandeln [...]

Das Beispiel ist:

// 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); 
} 

Sie von mpl::transform als Einnahme der Kompilierung-metaprogramming entspricht einem Funktionszeiger als zweites Template-Argument denken kann - add_reference<add_const<...>> auf jede der verschiedenen Arten angewendet wird in Tuple::elements. Dies konnte einfach nicht mit const ausgedrückt werden.

-1

Von was ich erinnere, es geht wie folgt, Sie können 3 costs (3 ist die Anzahl der Zweck) in einer Funktionsdeklaration schreiben.

vor dem Rückgabetyp, nach der Funktion und ihren Parametern und den Parametern selbst.

const am Ende einer Funktionssignatur bedeutet, dass die Funktion das Objekt übernehmen soll, von dem sie ein Member ist const. Praktisch bedeutet dies, dass Sie den Compiler bitten, zu überprüfen, ob die Elementfunktion die Objektdaten in keiner Weise ändert. Das bedeutet, dass der Compiler aufgefordert wird, zu überprüfen, dass keine Memberdaten direkt geändert werden, und dass keine Funktion aufgerufen wird, die nicht garantiert, dass das Objekt nicht geändert wird.

vor dem Rückgabetyp bedeutet, dass die Funktion, die zurückgegeben werden soll, eine Konstante sein sollte.

Parameter const bedeutet, dass der Parameter nicht geändert werden kann.

also ist der Unterschied hier, der erste Aufruf ist kein const, also geht es zum "non-cv", der zweite Aufruf ist ein const und geht so zu "const".

was ich denke, warum VC++ beide Male zur gleichen Funktion geht, ist, dass call_m explizit T() aufruft. M() denke, dass es nicht zu der const gehen sollte.

Verwandte Themen