dschatz
dschatz

Reputation: 1218

c++ access_once

I'm trying to implement the equivalent of the Linux macro ACCESS_ONCE in c++11. ACCESS_ONCE(x) takes the address of x, casts to a pointer to a volatile of the same type as x, then dereferences it. This forces the compiler to not optimize out accesses to x through this macro (and make the access occur only once here).

My attempt to do it in c++11 involves decltype:

#define ACCESS_ONCE(x) (*static_cast<decltype(x) volatile *>(&(x)))

This works for most cases but I use it once like so:

void foo(void **bar) {
  while (ACCESS_ONCE(*bar) != NULL)
    ;
}

This fails with an error:

'volatile' qualifiers cannot be applied to 'void*&'

What am I doing wrong?

Upvotes: 2

Views: 676

Answers (2)

bames53
bames53

Reputation: 88155

template<typename T>
inline T volatile &access_once(T &t) {
    return static_cast<T volatile &>(t);
}

This avoids macros, is simpler because the type deduction and reference removal is implicit in the template signature and it avoids the redundant address-of and deference operators (static casting between reference types is defined to do the same things as taking the address, casting and then dereferencing). It's just as performant and I don't think it depends on anything in C++11.

Upvotes: 7

Dirk Holsopple
Dirk Holsopple

Reputation: 8831

Change the macro to this:

#define ACCESS_ONCE(x) (*static_cast<std::remove_reference<decltype(x)>::type volatile *>(&(x)))

Dereferencing a pointer results in a reference. The macro is trying to cast it to a void *& volatile instead of a void * volatile like you want. You can't apply the volatile qualifier to a reference type so you have to use std::remove_reference to change it to the normal non-reference type.

Upvotes: 5

Related Questions