2015-07-31 5 views
6

Nach dieser answer, der folgende Code sollte ohne Fehler kompiliert werden:cv-kundiges Mitglied ist die Struktur nicht in ähnlicher Weise CV-qualifizierte

#include <type_traits> 

namespace 
{ 

struct A { int i; }; 

volatile A a{}; 
static_assert(std::is_volatile< decltype(a) >{}); 
static_assert(std::is_volatile< decltype(a.i) >{}); 

} 

aber es ist ein harter Fehler:

main.cpp:10:1: error: static_assert failed 
static_assert(std::is_volatile< decltype(a.i) >{}); 
^    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
1 error generated. 

Live example with clang 3.6.0 .

Ist es ein Clang Bug oder fehle ich etwas wesentliches?

ZUSÄTZLICH:

#include <type_traits> 

namespace 
{ 

struct A { int i; }; 

const A a{}; 
static_assert(std::is_const< decltype(a) >{}); 
static_assert(std::is_const< decltype(a.i) >{}); 

} 

Genau das gleiche Verhalten für letztere Code-Schnipsel.

ZUSÄTZLICH:

static_assert(std::is_volatile< std::remove_pointer_t< decltype(&a.i) > >{}); 

nicht einen Fehler verursachen.

+0

Außerdem ist 'static_assert' ohne Nachricht eine C++ 1z Erweiterung – snr

+0

@itsnotmyrealname Derselbe Fehler für C++ 11 http://coliru.stacked-crooked.com/a/3f2c7e25c543fb28 – Orient

Antwort

8

Dies ist das korrekte Verhalten; Die aktuelle decltype testet nicht, was Sie glauben, dass es testet. Sie müssen Ihre decltype ändern, wenn Sie für volatile -ness testen möchten.

Es ist möglich, einen Wert zu kopieren und volatile -ness zu löschen. Aber eine Referenz muss flüchtige Referenz-zu-flüchtige sein.

int foo() { 
    int i = a.i;   // volatile not needed 
    volatile int &i = a.i; // volatile needed 
} 

Die decltype ist a.i als R-Wert zu behandeln, kein L-Wert, tun, was decltype dem Standard entspricht und eine „naive“ Textanalyse tut und die Berichterstattung über die Art der A::i wie in den Quellcode geschrieben; daher ist decltype(a.i)int.

Putting () um einen Ausdruck in decltype ändert sein Verhalten (in der Regel gut für diese Art von Frage), geben uns einen Lvalue, wenn angemessen. Daher ist decltype((a.i))volatile int &.

Jetzt könnten Sie erwarten, dass is_volatile< volatile int & >::value wäre wahr. Aber es ist nicht. Wir müssen die Referenz entfernen, bevor wir die volatile -ness testen können.

static_assert(std::is_volatile< std::remove_reference_t<decltype((a.i))> >{}); 

Schließlich könnten Sie überrascht, dass volatile int & nicht flüchtig ist nach is_volatile. Aber ich denke, das liegt daran, dass Verweise wirklich sehr ähnlich wie Zeiger sind - und der "Zeiger" innerhalb einer Referenz nicht flüchtig ist, auch wenn das Objekt, auf das gezeigt wird, flüchtig ist. Das ist sowieso meine Theorie. const int& erfüllt auch nicht is_const.

+1

Dies ist richtig (' [C++ 14: 5.1.2/19] '). –

+0

@LightnessRacesinOrbit OK, akzeptiert. – Orient

+1

Die Semantik der Referenz ist fast wie * dereferenzierter Zeiger *. – Orient

Verwandte Themen