The following code does not compile in C++11 (nor C++14). I understand the error output from the compiler, but why isn't it allowed by the standard?
//main.cpp
#include <vector>
int main(void)
{
double a = 3.0;
double b = 3.0;
//It works with mere pointers
const double* ptrToConst = &a;
/***/ double* ptrToObj = &a;
// ptrToObj = ptrToConst; //Illegal : that's understandable…
ptrToConst = ptrToObj; //Works
//But the same doesn't work with vectors to pointers
std::vector<const double*> ptrsToConst = {&a, &b};
std::vector</***/ double*> ptrsToObj = {&a, &b};
// ptrsToObj = ptrsToConst; //Illegal : that's understandable
ptrsToConst = ptrsToObj; //Illegal : but why?!
}
The error comes from the line ptrsToConst = ptrsToObj
. Indeed, it does not seem possible to copy a vector of pointers std::vector<T*>
into a vector of pointers to constants std::vector<const T*>
. Note that in both cases, the pointers themselves are not constant.
Why would this operation be illegal? What would be the most elegant work around?
If I compile by invoking clang++ --std=c++11 main.cpp
, the following error message displays:
main.cpp:19:17: error: no viable overloaded '='
ptrsToConst = ptrsToObj; //Illegal : but why?!
~~~~~~~~~~~ ^ ~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h:436:7: note: candidate
function not viable: no known conversion from 'vector<double *, allocator<double *>>' to 'const
vector<const double *, allocator<const double *>>' for 1st argument
operator=(const vector& __x);
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h:448:7: note: candidate
function not viable: no known conversion from 'vector<double *, allocator<double *>>' to 'vector<const
double *, allocator<const double *>>' for 1st argument
operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h:470:7: note: candidate
function not viable: no known conversion from 'std::vector<double *>' to 'initializer_list<value_type>' (aka
'initializer_list<const double *>') for 1st argument
operator=(initializer_list<value_type> __l)
^
1 error generated.
Trying the same with gcc (g++) spawns similar error messages.
Apparently, the way vectors are implemented does not allow for the operation I am trying to perform. However that is a safe operation regarding const correctness, right?
You can do this, just not with operator=
. You need the assign
member function, which performs the conversion on each individual element.
ptrsToConst.assign(ptrsToObj.begin(), ptrsToObj.end());
Because it is the way std::vector
is implemented: the assignement operator requires the other operand to be of same type. And vector<double *>
and vector<const double *>
are different type because double
and const double
are different even if compatible types.
One could imagine to relax that requirement only to compatible types but it would be more complex to implement, when the implementation of standard containers is already complex enough (just read the vector header once...), and neither the writers of the library nor the standard comittee found it necessary.
If you really need it, you will have to write a custom implementation...
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