gpt4 book ai didi

c++ - 关于由 volatile 限定符限定的成员函数的问题

转载 作者:行者123 更新时间:2023-12-03 06:50:22 26 4
gpt4 key购买 nike

#include <iostream>
struct A{
A() = default;
A(volatile const A&){}
void show()const volatile {

}
};
int main(){
volatile A a;
//A b = std::move(a); // ill-formed
std::move(a).show(); //OK
}
考虑 example ,示例的结果超出了我对一些相关规则的理解。
对于 A b = std::move(a); ,它的格式不正确,因为它违反了以下规则,即:
dcl.init.ref#5.2

Otherwise, if the reference is an lvalue reference to a type that is not const-qualified or is volatile-qualified, the program is ill-formed.


这意味着,对 const volatile-qualified T 的左值引用不能绑定(bind)到任何 右值 即使它们是引用兼容的。 A b = std::move(a);显然违反了这条规则,因此它的格式不正确。
但是我不知道为什么要编译 std::move(a).show();不报错。根据这个规则:

For non-static member functions, the type of the implicit object parameter is

“lvalue reference to cv X” for functions declared without a ref-qualifier or with the & ref-qualifier



成员函数隐含对象参数的类型 show将是 volatile const A& .一般来说,它肯定违反了 [dcl.init.ref#5.2]。如果改变成员函数的定义 show到:
void show() volatile const& {

}
std::move(a).show();将是畸形的。所以在下面的规则中一定有一些魔法使 std::move(a).show();修改前编译 show .规则是:
over.match.funcs#general-5

For non-static member functions declared without a ref-qualifier, an additional rule applies:

even if the implicit object parameter is not const-qualified, an rvalue can be bound to the parameter as long as in all other respects the argument can be converted to the type of the implicit object parameter.



老实说,我真的不知道“在所有其他方面”这个词是什么意思?而“隐式对象参数的类型”指的是什么? “类型”是否指 volatile const A&或引用类型 volatile const A ?措辞非常模糊。总之, 对 const volatile T 的左值引用无法绑定(bind)到任何 右值 类型 T .那么,如何解读呢?
作为对比:
#include <iostream>
struct B{
void show(){}
};
int main(){
volatile B b;
std::move(b).show(); //ill-formed
}
show 的隐式对象参数的类型将是 B& , 根据 [over.match.funcs#general-5],即使忽略 const-qualifier ,由于它丢弃了 volatile-qualifier,它仍然是不正确的。 .从这个例子中可以看出,对于这句话“在所有其他方面,参数都可以转换为隐式对象参数的类型”,其中类型应引用 。引用类型 而不是引用所指的类型。如果魔法是这样的,仍然不足以使 std::move(a).show(); 形成良好的。
那么,如何解读这些问题呢?我不知道如何使用 [over.match.funcs#general-5] 来解释这两个示例。

最佳答案

struct A {
A() = default;
A(volatile const A &) {}
void show() const volatile {}
};

int main() {
volatile A a;
std::move(a).show(); // OK
}

成员函数的隐含对象参数 show()是,根据 [over.match.funcs]/4 , const volatile A& ,因此为了解决重载问题,我们可以根据 [over.match.funcs]/5 ,将数据成员函数视为
void show(const volatile A&);
现在,考虑到这一点,让我们首先简化示例,目的是:
  • 比较 A 的右值引用的原因似乎可以绑定(bind)到隐含的对象参数或类型const volatile A&但当参数用于常规自由函数时,更不用说相同类型的函数参数。

  • 因此,请考虑以下简化示例:
    #include <memory>

    struct A {
    void show() const volatile {}
    };

    void g(const volatile A &) { }

    int main() {
    volatile A a;

    g(std::move(a)); // (i) Error.
    std::move(a).show(); // (ii) OK.
    }
    GCC (10.1.0) 中 (i) 处的错误消息是:

    error: cannot bind non-const lvalue reference of type const volatile A& to an rvalue of type std::remove_reference<volatile A&>::type{aka volatile A}


    根据 [dcl.init.ref]/5.2,这是预期的(正如您自己所指出的) ,它不允许右值在初始化时绑定(bind)到 volatile引用,即使它们是 const -合格的。
    那么为什么(ii)被接受?或者反过来说,为什么 [dcl.init.ref]/5.2 的限制显然不适用于成员函数的隐式对象参数的类似情况?
    答案在于 [over.match.funcs]/5.1 ,其中包含声明没有 ref 限定符的成员函数的异常:

    [over.match.funcs]/5 [...] For non-static member functions declared without a ref-qualifier, an additional rule applies:

    • /5.1 even if the implicit object parameter is not const-qualified, an rvalue can be bound to the parameter as long as in all other respects the argument can be converted to the type of the implicit object parameter.

    [over.match.funcs ]/5.1 取消了 [dcl.init.ref]/5 关于右值(右值绑定(bind))的禁令,剩下的标准适用于参数(右值被忽略; volatile A)是否可以是 ("在所有其他方面") 转换为隐式对象参数 ( const volatile A&)。作为隐式对象参数,如上所示,在这种情况下始终是左值引用,“在所有其他方面”这里本质上意味着隐式对象参数是引用兼容的(根据 [dcl.init.ref]/4 )与(忽略右值)参数类型。
    // [over.match.funcs ]/5.1 special case: rvalue prohibition waived
    volatile A a; // argument: a
    const volatile A& aref = a; // ok, reference-compatible
    // ^^^^^^^^^^^^^^^^^ implicit object parameter
    可以说 [over.match.funcs]/5.1 可能更清楚,它适用于非 const 的情况。限定(通常)禁止从右值绑定(bind),并且 volatile -cv-qualification (通常)禁止从右值绑定(bind)。

    我们最终可以通过显式添加 & 来查询编译器这是否实际上是它用于允许 (ii) 的特定规则。 -ref-qualifier,根据 [over.match.funcs]/4.1 进行的更改对隐式对象参数的类型没有影响:
    #include <memory>

    struct A {
    void show() const volatile & {}
    };

    void g(const volatile A &) { }

    int main() {
    volatile A a;

    g(std::move(a)); // (i) Error.
    std::move(a).show(); // (ii') Error.
    }
    正如所料,如果我们添加 & - show() 的限定符过载,(ii)同样失败(i),尽管有另一个错误消息(GCC):

    error: passing std::remove_reference<volatile A&>::type {aka volatile A} as this argument discards qualifiers


    对于这个错误,Clang (10.0.0) 可以说有一个更现场的错误消息:

    error: this argument to member function show is an rvalue, but function has non-const lvalue ref-qualifier

    关于c++ - 关于由 volatile 限定符限定的成员函数的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64785336/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com