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

Why can't the compiler find the assignment operator?

提问人:Zebrafish 提问时间:7/6/2023 更新时间:7/6/2023 访问量:100

问:

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;


}

我得到的错误:

binary '=':未找到采用类型为右操作数的运算符 'MyPointermain::D'(或者没有可接受的转换)

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

C++ 赋值运算符

评论

0赞 Zebrafish 7/6/2023
@Yksisarvinen 不,它不是 && 是通用参考,而不是 r 值。两者兼而有之
4赞 Jarod42 7/6/2023
U&&将是通用参考,不是。C<U>&&
0赞 Zebrafish 7/6/2023
@Yksisarvinen哦,这不是一个通用的参考,如果它是 U 型,我会的

答:

5赞 Nelfeal 7/6/2023 #1
template <typename U>
void operator=(MyPointer<U>&& other)

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

因此,不能使用 lvalue 调用此函数。

如果要使用转发引用,但将其限制为实例,则可以执行如下操作: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) {
        // ...
    }

演示

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

6赞 463035818_is_not_an_ai 7/6/2023 #2

也许 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;
      |                    ^~~~~~~~~~~~

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

来自 cppreference

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

  1. 函数模板的函数参数,声明为右值引用,引用同一函数模板的 CV-Unqualified 类型模板参数:
  2. [...自动&&...]

这是一个转发参考

template <typename T> void foo(T&&);

这个不是

template <typename T> void bar(X<T>&&);