When you need std::remove_const
I ran across an interesting case where I needed to use std::remove_const
to ensure a template parameter wasn’t const by default. I had something like this:
With the library I was using, TooN 2.0.0 beta8, this resulted in a compile error. The error stated that when the vector returned from project()
was being created, the compiler couldn’t invoke assign to a read only location. A simplified declaration of project()
looks as follows:
What the project()
function returns is not important; what is important is the use of the template parameter Precision
in both the argument type and the return type. When I invoke operator[]
on a const Matrix object, the returned vector’s precision inherits the const.
When this vector is passed to the project()
function above, the function tries to create and return a Vector<3, const double>
which can only be initialized with a constexpr. Assigning to it via operator= or a constructor will not work to copy the data from the other vector.
There are several ways one can fix this, all of them involving removing the const qualifier from the Precision type on the returned vector.
It may seem like a simple solution would work:
Unfortunately, this requires the function be invoked as project<Size, Precision, Base, P2>(v);
which is undesirable.
Solution #1
The first solution is simple, but tedious if you have several functions with similar signatures:
std::remove_const<T>::type
is a type expression equal to the original type T
, but with any const qualifiers removed. In this way, const double
becomes simply double
.
Solution #2
Another solution is to prevent the creation of a Vector object with a const precision, the idea that a non-slice vector with const data isn’t very useful – you can’t even construct one properly. Generally the only time you would actually want a vector with const data is when that data is pointing to some already existing area in memory (a slice).
Consider the following toy code for a vector class:
When the Vector
object is backed by owned storage (StackBase
), the data is declared explicitly to be of a non-const type. Similarly, the return types of operator[]
are defined to be the const and non-const reference types. The SliceBase
, which handles references to un-owned data, retains the original templated type to allow pointing to constant data.
While this method prevents the creation of Vector objects with const owned data, it also means you don’t have to augment functions that interface with these objects to correct the return type.
0 comments: