2016-05-13 10 views
15

ich ein Testprogramm geschrieben:is_const funktioniert nicht als Referenz erwartet

#include <iostream> 
#include <type_traits> 
using namespace std; 
template<class T> 
void f(T&& t) 
{ 
    cout<<is_const<T>()<<endl; 
    //++t; 
} 
int main() { 
    const int i=0; 
    f(i); 
    return 0; 
} 

Es gibt „0“, T zeigt const nicht! Das ist seltsam. Dann modifiziert I f:

template<class T> 
void f(T&& t) 
{ 
    cout<<is_const<T>()<<endl; 
    ++t; 
} 

Dann gibt es Compiler-Fehler, sagen wir Modifizieren eines Nur-Lese-t. Also ist t änderbar oder nicht, überhaupt? Gibt es falsche Annahmen in meinem Programm?

+0

@ 101010 Die Verwendung ist korrekt. ['is_const'] (http://en.cppreference.com/w/cpp/types/is_const) hat einen geeigneten Konvertierungsoperator. – juanchopanza

+0

@juanchopanza Dank für die Info, die ich nicht wusste. – 101010

+0

@juanchopanza was in 'cout <() << endl;' würde es zwingen zu boolen? – xaxxon

Antwort

4

Ob t veränderbar ist, ist abhängig von der Art der T, die auf dem Typ der Variablen in geben Basis abgeleitet wird. In diesem Fall sind Sie in einem const int vorbei, so t ist vom Typ const int &, weil Sie es sind zu akzeptieren als Weiterleitungsreferenz.

Soweit warum is_const ist falsch zurück, das ist, weil T ein Referenztyp und Referenzen sind nie const.

14

Siehe std::is_const:

Wenn T ist ein const qualifizierte Typ (das heißt, const oder const volatile), liefert das Element konstanten Wert gleich wahr. Für jeden anderen Typ ist der Wert false.

t ist als forwarding references deklariert. Also für Ihren Code, T wird als const int& abgeleitet, die eine Referenz ist. Referenz kann nicht const-qualifizierte sein, es wird nicht const selbst sein. Genauer gesagt gibt es keine const Referenz (d. H. int& const), da die Referenz nicht erneut abgerufen werden konnte. const int& ist eine Referenz zu const int; und beachte, dass t somit nicht änderbar ist.

Vom Standard $8.3.2/1 References [dcl.ref]

Cv-qualifizierte Referenzen außer schlecht gebildet, wenn der cv-Qualifikations durch die Verwendung eines typedef-Namen eingeführt werden ([dcl.typedef], [temp .param]) oder declltype-specifier ([dcl.type.simple]), wobei die cv-Qualifiers ignoriert werden.

Weitere Beispiele aus cppreference:

std::cout << std::is_const<int>::value << '\n'; // false 
std::cout << std::is_const<const int>::value << '\n'; // true 
std::cout << std::is_const<const int*>::value << '\n'; // false 
std::cout << std::is_const<int* const>::value << '\n'; // true 
std::cout << std::is_const<const int&>::value << '\n'; // false 
3

Ihre Template-Funktion (das heißt, f) als Parameter eine forwarding reference (a.k.a universelle Referenz). Die Regeln, die den Abzug von T bestimmen, werden als reference collapsing rules bezeichnet.Diese Regeln sind unten zusammengefasst:

  1. T&& wird T&
  2. T&&& wird T&
  3. T&&& wird T&
  4. T&&&&T&&
wird

nun nach dem Referenzregeln kollabiert, wenn Sie als Parameter fint const i liefern, wird T-int const& abgezogen.

Nach der C++ Standardtabelle 52 is_const würde true bewerten, wenn Tconst qualifizierte ist.

enter image description here

Weiterhin ist in der C++ Standard §20.13.4.3/p5 Typ Eigenschaften [meta.unary.prop] gibt es das folgende Beispiel, wie is_const Typ Merkmal funktioniert:

[ Beispiel:

is_const<const volatile int>::value // true 
is_const<const int*>::value // false 
is_const<const int&>::value // false 
is_const<int[3]>::value // false 
is_const<const int[3]>::value // true 

- Ende Beispiel]

Wie Sie in der dritten Zeile sehen können, ist unser Fall is_const wertet false aus. Warum? Da der Typ, der als Vorlageparameter an is_const übergeben wird, ein Referenztyp ist. Nun, Referenzen sind inhärent const in dem Sinne, dass Sie nicht ändern können, worauf sie sich beziehen, aber sie sind nicht const qualifiziert. Somit wird is_const mit einem Referenztyp zu false ausgewertet.

0

Die oberste Antwort lautet, dass Referenzen nicht cv-qualifiziert sind. Nur die Typen, auf die sie sich beziehen, können cv-qualifiziert sein.

Aber das ist einer der Zeiten, wenn die Platzierung des Wortes const zählt. Wenn Sie anrufen:

template<class T> 
void f(T&& t) 

mit einem L-Wert vom Typ const int, was bedeutet T bekommen abgeleitet? Sie könnten sagen const int& (was richtig ist), aber es sieht aus wie dieser Typ ist const (int&). Daher ist die mögliche Verwirrung über Tconst.

Aber wenn stattdessen sagte man es als int const& abgeleitet (die die gleiche Art ist wie zuvor), hier gibt es keine mögliche Verwirrung und es ist vielleicht weniger überraschend, warum std::is_const<int const&>std::false_type ist.

0

Mögliche Lösung könnte sein, const Typ in Überlastung abzufangen:

template<class T> 
void f(T&& t) 
{ 
    ++t; 
} 

template<class T> 
void f(const T& t) 
{ 
    std::cout << "const here" << std::endl; 
} 

Dann Verweise auf const Objekte werden durch eine zweite Funktion behandelt werden.

Verwandte Themen