当概念用于源类型时,调用移动赋值而不是复制
Move assignemnt is called instead of copy, when concepts are used for source type
在下面的代码中,当我将源从 CAssign
作为赋值运算符的源更改为 AnyThing auto
时,将调用移动构造函数而不是复制。
我猜这与常量有关,但我可能错了。是什么原因导致的以及如何实现我想要的?
#include <iostream>
#include <concepts>
template<typename T>
concept AnyThing = true;
struct CAssign
{
CAssign() = default;
CAssign& operator=(const CAssign& source)
{
std::cout << "Copy called\n";
return *this;
}
CAssign& operator=(CAssign&& source)
{
std::cout << "Move called\n";
return *this;
}
};
int main() {
CAssign a1, a2;
a1 = a2;
}
编辑:
这是我所做的改变:
CAssign& operator=(const AnyThing auto& source)
//...
CAssign& operator=(AnyThing auto&& source)
用 Clang 和 GCC 都试过了。调用移动而不是复制。
在
CAssign& operator=(CAssign&& source)
引用参数是右值引用。仅当给定的参数是右值(不在 a1 = a2;
中)时才会调用它。这是一个移动赋值运算符及其正常行为方式。
有
CAssign& operator=(Anything auto&& source)
或者只是
CAssign& operator=(auto&& source)
这是不是右值引用参数。 auto
作为模板参数的short-hand,如果函数的模板参数T
直接用作函数参数的T&&
,那么它是转发参考.
转发引用可以匹配右值或左值。如果它匹配一个右值,函数参数将是一个右值引用。如果它匹配一个左值,它将是一个左值引用。
在你的例子中a1 = a2;
right-hand 边是一个左值,所以它会调用特化
CAssign& operator=<CAssign&>(CAssign& source)
auto
版本定义的函数模板。此重载优于您定义的复制赋值重载,因为它不需要参数中的 const
转换。如果您将 a2
的类型设置为 const
,则复制赋值运算符将是首选,因为它不是函数模板。
特别是这意味着这样的 operator=
重载 不是 移动赋值运算符(或复制赋值运算符)。
您不应定义采用任何类型的模板 operator=
重载,或者如果您这样做,请添加类型不匹配的约束 CAssign
.
在下面的代码中,当我将源从 CAssign
作为赋值运算符的源更改为 AnyThing auto
时,将调用移动构造函数而不是复制。
我猜这与常量有关,但我可能错了。是什么原因导致的以及如何实现我想要的?
#include <iostream>
#include <concepts>
template<typename T>
concept AnyThing = true;
struct CAssign
{
CAssign() = default;
CAssign& operator=(const CAssign& source)
{
std::cout << "Copy called\n";
return *this;
}
CAssign& operator=(CAssign&& source)
{
std::cout << "Move called\n";
return *this;
}
};
int main() {
CAssign a1, a2;
a1 = a2;
}
编辑: 这是我所做的改变:
CAssign& operator=(const AnyThing auto& source)
//...
CAssign& operator=(AnyThing auto&& source)
用 Clang 和 GCC 都试过了。调用移动而不是复制。
在
CAssign& operator=(CAssign&& source)
引用参数是右值引用。仅当给定的参数是右值(不在 a1 = a2;
中)时才会调用它。这是一个移动赋值运算符及其正常行为方式。
有
CAssign& operator=(Anything auto&& source)
或者只是
CAssign& operator=(auto&& source)
这是不是右值引用参数。 auto
作为模板参数的short-hand,如果函数的模板参数T
直接用作函数参数的T&&
,那么它是转发参考.
转发引用可以匹配右值或左值。如果它匹配一个右值,函数参数将是一个右值引用。如果它匹配一个左值,它将是一个左值引用。
在你的例子中a1 = a2;
right-hand 边是一个左值,所以它会调用特化
CAssign& operator=<CAssign&>(CAssign& source)
auto
版本定义的函数模板。此重载优于您定义的复制赋值重载,因为它不需要参数中的 const
转换。如果您将 a2
的类型设置为 const
,则复制赋值运算符将是首选,因为它不是函数模板。
特别是这意味着这样的 operator=
重载 不是 移动赋值运算符(或复制赋值运算符)。
您不应定义采用任何类型的模板 operator=
重载,或者如果您这样做,请添加类型不匹配的约束 CAssign
.