According to this answer, the following code should be compiled without error:
#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) >{});
}
but there is a hard error:
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.
Is it a clang bug or am I missing something substantial?
ADDITIONAL:
#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) >{});
}
Exactly the same behaviour for the latter code snippet.
ADDITIONAL:
static_assert(std::is_volatile< std::remove_pointer_t< decltype(&a.i) > >{});
not cause an error.
This is the correct behaviour; the current decltype
isn't testing what you think it tests. You have to change your decltype
if you want to test for volatile
-ness.
It is possible to copy a value out and drop volatile
-ness. But a reference must be volatile reference-to-volatile.
int foo() {
int i = a.i; // volatile not needed
volatile int &i = a.i; // volatile needed
}
The decltype
is treating doing what a.i
as an rvalue, not an lvalue,decltype
does by default and is doing a "naive" text analysis and reporting the type of A::i
as written in the source code; therefore, decltype(a.i)
is int
.
Putting ()
around an expression in decltype
changes its behaviour (in good ways usually, for this kind of question), giving us an lvalue when appropriate. Therefore, decltype(( a.i ))
is volatile int &
.
Now, you might expect that is_volatile< volatile int & >::value
would be true. But it's not. We need to remove the reference before we can test for the volatile
-ness.
static_assert(std::is_volatile< std::remove_reference_t<decltype((a.i))> >{});
Finally, you might be surprised that volatile int &
isn't volatile according to is_volatile
. But I guess it's because references are really very like pointers - and the 'pointer' inside a reference isn't volatile, even if the object pointed to is volatile. That's my theory anyway. const int&
also does not satisfy is_const
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With