I'm trying to wrap my head around a copy assignment operator issue. I am at a loss what is really going on, though I have some ideas (listed at the end). This is a problem since I am using a 3rd party library with no control on its classes.
Lets say you have a templated container with copy assignment operator. This operator accepts another container with a different template, and tries to static_cast the other type.
template <class U>
vec2<T>& operator=(const vec2<U>& v) {
x = static_cast<T>(v.x);
y = static_cast<T>(v.y);
return *this;
}
This is fine for simple assignment, however when using references for T, you get a compile error about const value types. If you add another overload that accepts a non-const reference, it will compile and work.
I've made a simple example which should help illustrate the issue.
template <class T>
struct vec2 final {
vec2(T x_, T y_)
: x(x_)
, y(y_) {
}
template <class U>
vec2(const vec2<U>& v)
: x(static_cast<T>(v.x))
, y(static_cast<T>(v.y)) {
}
template <class U>
vec2<T>& operator=(const vec2<U>& v) {
if (this == &v)
return *this;
x = static_cast<T>(v.x);
y = static_cast<T>(v.y);
return *this;
}
// Fix :
/*
template <class U>
vec2<T>& operator=(vec2<U>& v) {
x = static_cast<T>(v.x);
y = static_cast<T>(v.y);
return *this;
}
*/
T x;
T y;
};
And how I am trying to use it :
int main(int, char**) {
vec2<int> v0 = { 0, 0 };
vec2<int> v1 = { 1, 1 };
vec2<int&> test[] = { { v0.x, v0.y }, { v1.x, v1.y } };
vec2<int> muh_vec2 = { 2, 2 };
test[0] = muh_vec2;
printf("{ %d, %d }\n", test[0].x, test[0].y);
return 0;
}
The latest AppleClang will generate the following error :
main4.cpp:18:7: error: binding value of type 'const int' to reference to type 'int'
drops 'const' qualifier
x = static_cast<T>(v.x);
^ ~~~
main4.cpp:63:10: note: in instantiation of function template specialization 'vec2<int
&>::operator=<int>' requested here
test[0] = muh_vec2;
^
What I understand from this, is that somehow the compiler is trying to assign by const value. But why and is there a non-intrusive solution to this issue?
I did find a similar question here : Template assignment operator overloading mystery
My conclusion after reading the issue is : maybe a default assignment operator is causing the issue? I still do not understand why though :/
Here is an online example : https://wandbox.org/permlink/Fc5CERb9voCTXHiN
x = static_cast<std::remove_reference_t<T>>(v.x)
perhaps. Or maybe even simplyx = v.x;
and rely on implicit conversions. – Igor Tandetnikvec2<T>
simply wasn't designed to be used with a reference type forT
. So one way to fix the problem without modifyingvec
is simply to avoid using it this way. – Igor Tandetnik