0

在 C++ 20 标准中,类模板的构造函数std::reference_wrapper是一个模板。

template<class U>
constexpr reference_wrapper(U&&) noexcept(see below ); 

而赋值运算符不是模板

constexpr reference_wrapper& operator=(const reference_wrapper& x) noexcept;

这些特殊成员函数之间存在这种差异(模板和非模板)的原因是什么?

另一方面,我使用 Visual C++ 2019 尝试了以下程序。

#include <iostream>
#include <functional>

struct A
{
    void f() const { std::cout << "A::f()\n"; }
    virtual void g() const { std::cout << "A::g()\n"; }
};

struct B : A
{
    void f() const { std::cout << "B::f()\n"; }
    void g() const override { std::cout << "B::g()\n"; }
};

int main()
{
    B b;

    std::reference_wrapper<A> r( b );

    r.get().f();
    r.get().g();


    r = std::reference_wrapper<B>( b );
}

并且编译器没有发出与赋值运算符相关的错误消息。

它是编译器的错误还是我错过了什么?

4

1 回答 1

4

如果std::reference_wrapper<T>有一个构造函数接受T&,那么它会导致错误,比如std::reference_wrapper<const T>能够绑定到临时类型的T。所以,最初有两个构造函数(除了拷贝构造函数):一个 take T&,另一个taking T&&,它被定义为delete ,确保会发生编译错误。

然而,有人指出,这并不是我们真正想要的:如果std::reference_wrapper<T>完全没有构造函数来接受 type 的右值T,而不是删除构造函数,那就更好了。这是LWG 2993(您会注意到cppreference 页面底部提到了此问题。)因此,构造函数已更改为适当禁用 SFINAE 的模板。

一旦为构造函数解决了这些问题,赋值运算符只需要一个重载reference_wrapper。当编译器形成隐式转换序列时,转换问题将由构造函数逻辑处理。

于 2020-05-18T23:33:42.583 回答