非模板 std::reference_wrapper 赋值运算符和模板构造函数

non-template std::reference_wrapper assignment operator and template constructor

提问人:Vlad from Moscow 提问时间:5/19/2020 更新时间:5/19/2020 访问量:142

问:

在 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 );
}

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

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

C++ 模板 赋值运算符 C++20 引用包装器

评论


答:

4赞 Brian Bi 5/19/2020 #1

如果有一个构造函数接受 ,那么它会导致错误,例如能够绑定到类型的临时 。因此,最初有两个构造函数(复制构造函数除外):一个采用 ,另一个采用 ,它被定义为已删除,确保会发生编译错误。std::reference_wrapper<T>T&std::reference_wrapper<const T>TT&T&&

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

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

评论

0赞 Vlad from Moscow 5/19/2020
但是该标准不允许构造函数接受 std::reference_wrapper 类型的对象。
0赞 Brian Bi 5/19/2020
@VladfromMoscow有一个复制构造函数,不是吗?
0赞 Vlad from Moscow 5/19/2020
复制构造函数也是非模板构造函数。
0赞 Brian Bi 5/19/2020
@VladfromMoscow是的,有一个复制构造函数和一个模板转换构造函数,但我不明白你要去哪里。