The restrict
keyword in C is missing in C++, so out of interest I was looking for a way to emulate the same feature in C++.
Specifically, I would like the following to be equivalent:
// C void func(S *restrict a, S *restrict b) // C++ void func(noalias<S, 1> a, noalias<S, 2> b)
where noalias<T, n>
T*
when accessed with ->
and *
T*
(so that the function can be called as func(t1, t2)
, where t1
and t2
are both of type T*
)n
specifies the "aliasing class" of the variable, so that variables of type noalias<T, n>
and noalias<T, m>
may be assumed never to alias for n != m.Here is my deeply flawed solution:
template <typename T, int n> class noalias { struct T2 : T {}; T *t; public: noalias(T *t_) : t(t_) {} T2 *operator->() const {return static_cast<T2*>(t);} // <-- UB };
When accessed with ->
, it casts the internally-stored T*
to a noalias<T, n>::T2*
and returns that instead. Since this is a different type for each n
, the strict aliasing rule ensures that they will never alias. Also, since T2
derives from T
, the returned pointer behaves just like a T*
. Great!
Even better, the code compiles and the assembly output confirms that it has the desired effect.
The problem is the static_cast
. If t
were really pointing to an object of type T2
then this would be fine. But t
points to a T
so this is UB. In practice, since T2
is a subclass which adds nothing extra to T
it will probably have the same data layout, and so member accesses on the T2*
will look for members at the same offsets as they occur in T
and everything will be fine.
But having an n
-dependent class is necessary for strict aliasing, and that this class derives from T
is also necessary so that the pointer can be treated like a T*
. So UB seems unavoidable.
Can this be done in c++14 without invoking UB - possibly using a completely different idea?
If not, then I have heard about a "dot operator" in c++1z; would it be possible with this?
If the above, will something similar to noalias
be appearing in the standard library?
From the article: "Strict aliasing is an assumption, made by the C (or C++) compiler, that dereferencing pointers to objects of different types will never refer to the same memory location (i.e. alias each other.)"
In the C programming language (after 99 standard), a new keyword is introduced known as restrict. restrict keyword is mainly used in pointer declarations as a type qualifier for pointers. It doesn't add any new functionality. It is only a way for programmer to inform about an optimization that compiler can make.
C # in Telugu The restrict keyword is used for pointer declarations as a type quantifier of the pointer. This keyword does not add new functionalities. Using this the programmer can inform about an optimization that compiler can make.
In the C programming language, restrict is a keyword, introduced by the C99 standard, that can be used in pointer declarations. By adding this type qualifier, a programmer hints to the compiler that for the lifetime of the pointer, no other pointer will be used to access the object to which it points.
You could use the __restrict__
GCC extension for un/aliasing.
From the docs
In addition to allowing restricted pointers, you can specify restricted references, which indicate that the reference is not aliased in the local context.
void fn (int *__restrict__ rptr, int &__restrict__ rref) { /* ... */ }
In the body of fn
, rptr
points to an unaliased integer and rref refers to a (different) unaliased integer. You may also specify whether a member function's this pointer is unaliased by using __restrict__
as a member function qualifier.
void T::fn () __restrict__ { /* ... */ }
Within the body of T::fn
, this will have the effective definition T *__restrict__ const this
. Notice that the interpretation of a __restrict__
member function qualifier is different to that of const
or volatile
qualifier, in that it is applied to the pointer rather than the object. This is consistent with other compilers which implement restricted pointers.
As with all outermost parameter qualifiers, __restrict__
is ignored in function definition matching. This means you only need to specify __restrict__
in a function definition, rather than in a function prototype as well.
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