引用模板类型的赋值运算符需要非常量重载
Assignment operator to reference template type requires non-const overload
我正在努力解决复制赋值运算符的问题。尽管我有一些想法(最后列出),但我不知道到底发生了什么。这是一个问题,因为我使用的是无法控制其 类.
的第三方库
假设您有一个带有复制赋值运算符的模板化容器。此运算符接受另一个具有不同模板的容器,并尝试 static_cast 其他类型。
template <class U>
vec2<T>& operator=(const vec2<U>& v) {
x = static_cast<T>(v.x);
y = static_cast<T>(v.y);
return *this;
}
这对于简单的赋值来说很好,但是当使用 T 的引用时,您会收到有关 const 值类型的编译错误。如果您添加另一个接受非常量引用的重载,它将编译并工作。
我做了一个简单的例子,应该有助于说明问题。
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;
};
以及我是如何尝试使用它的:
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;
}
最新的 AppleClang 会产生以下错误:
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;
^
据我了解,编译器试图以某种方式通过 const 值进行分配。但是为什么以及是否有针对此问题的非侵入式解决方案?
我确实在这里找到了类似的问题:Template assignment operator overloading mystery
阅读问题后我的结论是:可能是默认赋值运算符导致了问题?我仍然不明白为什么:/
template <class U>
vec2<T>& operator=(const vec2<U>& v)
在此方法中,v
是右侧常量视图的名称。如果 U
是 int
,那么 v.x
是 const int
.
如果T
是int&
,那么this->x
是int&
。
this->x = static_cast<int&>(v.x);
这显然是非法的:您不能将 const int 静态转换为非 const 引用。
一般解决方案基本上需要重建 std::tuple
或 std::pair
机器。可以用SFINAE来bootstrap了。但总的来说,包含引用的结构和包含值的结构通常是完全不同的东西;对两者使用一个模板是有问题的。
template <class T>
struct vec2 final {
template<class Self,
std::enable_if_t<std::is_same<std::decay_t<Self>, vec2>>{}, bool> =true
>
friend auto as_tuple( Self&& self ){
return std::forward_as_tuple( std::forward<Self>(self).x, std::forward<Self>(self).y );
}
然后我们可以做 SFINAE 测试来确定 as_tuple(LHS)=as_tuple(RHS)
是否有效。
为构建做这个是另一个痛苦,因为 LHS 的元组类型需要在可构建性测试工作之前进行按摩。
您编写的代码越通用,需要的工作就越多。在编写无限通用代码之前考虑实际用例。
我正在努力解决复制赋值运算符的问题。尽管我有一些想法(最后列出),但我不知道到底发生了什么。这是一个问题,因为我使用的是无法控制其 类.
的第三方库假设您有一个带有复制赋值运算符的模板化容器。此运算符接受另一个具有不同模板的容器,并尝试 static_cast 其他类型。
template <class U>
vec2<T>& operator=(const vec2<U>& v) {
x = static_cast<T>(v.x);
y = static_cast<T>(v.y);
return *this;
}
这对于简单的赋值来说很好,但是当使用 T 的引用时,您会收到有关 const 值类型的编译错误。如果您添加另一个接受非常量引用的重载,它将编译并工作。
我做了一个简单的例子,应该有助于说明问题。
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;
};
以及我是如何尝试使用它的:
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;
}
最新的 AppleClang 会产生以下错误:
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;
^
据我了解,编译器试图以某种方式通过 const 值进行分配。但是为什么以及是否有针对此问题的非侵入式解决方案?
我确实在这里找到了类似的问题:Template assignment operator overloading mystery
阅读问题后我的结论是:可能是默认赋值运算符导致了问题?我仍然不明白为什么:/
template <class U>
vec2<T>& operator=(const vec2<U>& v)
在此方法中,v
是右侧常量视图的名称。如果 U
是 int
,那么 v.x
是 const int
.
如果T
是int&
,那么this->x
是int&
。
this->x = static_cast<int&>(v.x);
这显然是非法的:您不能将 const int 静态转换为非 const 引用。
一般解决方案基本上需要重建 std::tuple
或 std::pair
机器。可以用SFINAE来bootstrap了。但总的来说,包含引用的结构和包含值的结构通常是完全不同的东西;对两者使用一个模板是有问题的。
template <class T>
struct vec2 final {
template<class Self,
std::enable_if_t<std::is_same<std::decay_t<Self>, vec2>>{}, bool> =true
>
friend auto as_tuple( Self&& self ){
return std::forward_as_tuple( std::forward<Self>(self).x, std::forward<Self>(self).y );
}
然后我们可以做 SFINAE 测试来确定 as_tuple(LHS)=as_tuple(RHS)
是否有效。
为构建做这个是另一个痛苦,因为 LHS 的元组类型需要在可构建性测试工作之前进行按摩。
您编写的代码越通用,需要的工作就越多。在编写无限通用代码之前考虑实际用例。