为什么编译器找不到赋值运算符?

Zeb*_*ish 4 c++ assignment-operator

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;


}
Run Code Online (Sandbox Code Playgroud)

我得到的错误:

二进制“=”:找不到采用“MyPointermain::D”类型的右侧操作数的运算符(或者没有可接受的转换)

编译器为我使用的特定类型实例化赋值运算符,因此即使它删除了默认运算符,实例化的运算符也应该在那里。

for*_*818 6

也许gcc 的错误有助于进一步阐明这一点:

<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;
      |                    ^~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

您的MyPointer<U>&&不是转发参考。它是一个右值引用。

来自cppreference

转发引用是一种特殊的引用,它保留函数参数的值类别,从而可以通过std::forward. 转发参考是:

  1. 函数模板的函数参数声明为对同一函数模板的 cv 非限定类型模板参数的右值引用:
  2. [... 汽车&& ...]

这是转发参考

template <typename T> void foo(T&&);
Run Code Online (Sandbox Code Playgroud)

这个不是

template <typename T> void bar(X<T>&&);
Run Code Online (Sandbox Code Playgroud)


Nel*_*eal 5

template <typename U>
void operator=(MyPointer<U>&& other)
Run Code Online (Sandbox Code Playgroud)

在此,MyPointer<U>&&不做转发参考。它是对 some 的右值引用MyPointer<U>,其中U是从参数中推导出来的。

因此,您无法使用左值调用此函数。

如果您想使用转发引用但将其限制为实例MyPointer,那么您可以执行以下操作:

// 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) {
        // ...
    }
Run Code Online (Sandbox Code Playgroud)

演示

(或者如果您不能使用概念,请使用 SFINAE)