英文:
Why can't the compiler find the assignment operator?
问题
template <typename T>
class MyPointer
{
public:
template <typename U>
void operator=(MyPointer<U>&& other)
{
// Your code here...
}
char* get() const { return pointer; }
private:
char* pointer;
};
int main()
{
struct B {};
struct D : B{};
MyPointer<B> my_pointer_b;
MyPointer<D> my_pointer_d;
my_pointer_b = my_pointer_d;
}
错误信息:
二进制 '=':找不到接受右操作数类型为 'MyPointermain::D' 的运算符(或没有可接受的转换)
编译器会为你使用的具体类型实例化赋值运算符,所以即使删除了默认赋值运算符,实例化的赋值运算符也应该存在。
英文:
template <typename T>
class MyPointer
{public:
template <typename U>
void operator=(MyPointer<U>&& other)
{
}
char* get() const { return pointer; }
private:
char* pointer;
};
int main()
{
struct B {};
struct D : B{};
MyPointer<B> my_pointer_b;
MyPointer<D> my_pointer_d;
my_pointer_b = my_pointer_d;
}
The error I get:
> binary '=': no operator found which takes a right-hand operand of type
> 'MyPointer<main::D>' (or there is no acceptable conversion)
The compiler instantiates the assignment operator for the particular type that I use, so even if it deleted the default one the instantiated one should be there.
答案1
得分: 6
或许与 gcc 出现的错误 有关,能更清楚地说明这个问题:
<source>:24:20: 错误:无法将类型为 'MyPointer<main()::D>&&' 的右值引用绑定到类型为 'MyPointer<main()::D>' 的左值
24 | my_pointer_b = my_pointer_d;
| ^~~~~~~~~~~~
你的 MyPointer<U>&&
不是转发引用。它是右值引用。
来自 cppreference:
> 转发引用是一种特殊类型的引用,它保留了函数参数的值类别,使得可以通过 std::forward
进行转发。转发引用可以是以下两种情况之一:
> 1) 函数模板的函数参数,声明为同一函数模板的模板参数的右值引用到非 cv 限定类型:
> 2) [... auto&& ...]
这是一个转发引用:
template <typename T> void foo(T&&);
这个不是:
template <typename T> void bar(X<T>&&);
英文:
Perhaps the error with gcc helps to shed more light on this:
<source>:24:20: error: cannot bind rvalue reference of type 'MyPointer<main()::D>&&' to lvalue of type 'MyPointer<main()::D>'
24 | my_pointer_b = my_pointer_d;
| ^~~~~~~~~~~~
Your MyPointer<U>&&
is not a forwarding reference. Its a rvalue reference.
From cppreference:
> Forwarding references are a special kind of references that preserve the value category of a function argument, making it possible to forward it by means of std::forward
. Forwarding references are either:
> 1) function parameter of a function template declared as rvalue reference to cv-unqualified type template parameter of that same function template:
> 2) [... auto&& ...]
This is a forwarding reference
template <typename T> void foo(T&&);
This one is not
template <typename T> void bar(X<T>&&);
答案2
得分: 5
template <typename U>
void operator=(MyPointer<U>&& other)
在这里,MyPointer<U>&&
不是一个转发引用。它是对某个 MyPointer<U>
的右值引用,其中 U
是从参数中推导出来的。
因此,您不能使用左值调用这个函数。
如果您想要使用一个转发引用,但要将其限制为 MyPointer
实例,可以像这样做:
// 前向声明
template <typename T>
class MyPointer;
template <typename T>
struct IsMyPointerInstance : std::false_type {};
template <typename T>
struct IsMyPointerInstance<MyPointer<T>> : std::true_type {};
template <typename T>
concept MyPointerInstance = IsMyPointerInstance<std::remove_cvref_t<T>>::value;
template <typename T>
class MyPointer {
public:
template <typename U> requires MyPointerInstance<U>
void operator=(U&& other) {
// ...
}
}
(或者如果您不能使用概念,可以使用 SFINAE)
英文:
template <typename U>
void operator=(MyPointer<U>&& other)
In this, MyPointer<U>&&
is not a forwarding reference. It's an rvalue reference to some MyPointer<U>
, where U
is deduced from the argument.
As a result, you cannot call this function with an lvalue.
If you want to use a forwarding reference but constrain it to a MyPointer
instance, then you can do something like this:
// forward declaration
template <typename T>
class MyPointer;
template <typename T>
struct IsMyPointerInstance : std::false_type {};
template <typename T>
struct IsMyPointerInstance<MyPointer<T>> : std::true_type {};
template <typename T>
concept MyPointerInstance = IsMyPointerInstance<std::remove_cvref_t<T>>::value;
template <typename T>
class MyPointer {
public:
template <typename U> requires MyPointerInstance<U>
void operator=(U&& other) {
// ...
}
(or use SFINAE if you can't use concepts)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论