当前位置: 首页 > 知识库问答 >
问题:

关于volatile限定符限定的成员函数的一个问题

束帅
2023-03-14
#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
}

考虑示例,示例的结果超出了我对一些相关规则的理解。

对于A b=std::移动(a);,它格式错误,因为它违反了以下规则,即:
dcl.init.ref#5.2

否则,如果引用是对非const限定或易失性限定类型的左值引用,则程序格式错误。

这意味着,对常量T的左值引用不能绑定到任何右值,即使它们是引用兼容的<代码>AB=std::移动(A)显然违反了这条规则,因此它的格式不正确。

但是我不知道为什么要编译std::move(a)。show() 无错误报告。根据这条规则:

对于非静态成员函数,隐式对象参数的类型为

“对cv X的左值引用”,用于声明没有ref限定符或带有

成员函数show的隐式对象参数的类型将是volatile const A

void show() volatile const& {

}

std::mobile(a). show();将是格式错误的。因此,下面的规则中一定有一些魔法使std::mobile(a). show();在更改show之前进行编译。规则是:
over.match.funcs#general-5

对于未使用ref限定符声明的非静态成员函数,另一条规则适用:

即使隐式对象参数不是const限定的,只要在所有其他方面参数都可以转换为隐式对象参数的类型,就可以将右值绑定到该参数。

老实说,我真的不知道“在所有其他方面”是什么意思?“隐式对象参数的类型”指的是什么?“类型”指的是挥发性常数吗

作为对比:

#include <iostream>
struct B{
  void show(){}
};
int main(){
  volatile B b;
  std::move(b).show();  //ill-formed
}

show的隐式对象参数的类型将是B

那么,如何解释这些问题呢?我不知道如何使用[over.match.funcs#general-5]来解释这两个例子。


共有1个答案

胡元忠
2023-03-14
struct A {
    A() = default;
    A(volatile const A &) {}
    void show() const volatile {}
};

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

根据[over.match.funcs]/4,成员函数show()的隐含对象参数是const volatile A

void show(const volatile A&);

现在,考虑到这一点,让我们首先简化示例,目的是:

  • 比较为什么A的右值引用似乎可以绑定到隐含的对象参数或类型const易失性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)处的错误信息为:

错误:无法绑定const挥发性A类型的非const左值引用

根据[dcl.init.ref]/5.2,这是预期的(正如您自己所指出的),它不允许Rvalue在初始化时绑定到volatile引用,即使它们是const限定的。

那么为什么(ii)被接受?或者,反过来说,[dcl.init.ref]/5.2的限制为什么显然不适用于成员函数的隐式对象参数的类似情况?

答案就在[over.match.funcs]/5.1中,其中包含一个不带ref限定符的成员函数的异常:

[over.match.funcs]/5[…]对于未使用ref限定符声明的非静态成员函数,另一条规则适用:

  • /5.1即使隐式对象参数不是const限定的,只要在所有其他方面参数可以转换为隐式对象参数的类型,就可以将右值绑定到参数

[over.match.funcs]/5.1删除了[dcl.init.ref]/5对右值(右值绑定)的禁止,剩下的标准应用于参数(右值忽略;volatile A)是否可以(“在所有其他方面”)转换为隐式对象参数(const volatile A)

// [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限定(通常)禁止from-右值绑定的情况,也适用于voll-cv限定(通常)禁止from-右值绑定。

通过显式添加

#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.
}

正如预期的那样,如果我们添加一个

错误:传递std::remove_引用

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

错误:成员函数show的此参数是右值,但函数具有非常量左值ref限定符

 类似资料:
  • 6. volatile限定符 现在探讨一下编译器优化会对生成的指令产生什么影响,在此基础上介绍C语言的volatile限定符。看下面的例子。 例 19.7. volatile限定符 /* artificial device registers */ unsigned char recv; unsigned char send; /* memory buffer */ unsigned char

  • 这是我上一篇文章的后续文章 参考非静态成员函数 在下面 const-、vole-和ref限定的成员函数 非静态成员函数可以在没有ref限定符的情况下声明,...在重载解析期间,X类的非静态cv限定成员函数被处理如下: 无ref限定符:隐式对象参数具有对cv限定X的类型左值引用,并且还允许绑定右值隐式对象参数 为了进一步探索这一点,我试用了上面链接中提供的源代码,如下所示: 我已经在每个基于引用限定

  • 如果没有其他重载(比如,

  • 根据文件,上面说 在重载解析期间,类X的非静态cv限定成员函数被视为一个函数,如果它没有ref限定符或具有左值ref限定符,则该函数将左值引用类型的隐式参数带到cv限定X。否则(如果它有rvalue ref限定符),它将被视为一个函数,将rvalue reference类型的隐式参数作为cv限定的X。 问题: 没有任何ref限定符的成员函数如何?它们将被视为使用左值限定符隐式声明的函数。我说得对吗

  • 其中T是模板参数。它是这样实现的: 并按预期工作。当我试图将和的定义移到类体之外时,问题就出现了,如下所示: 在箭头标记的一行表达了它的不满:

  • 在上一小节中的表格中,我们知道 . 可以匹配除换行符以外的任意字符,使用.匹配下列文本: expression 但是.每次只匹配一个字符,如果想一次匹配多个,则要使用限定符 限定符 作用 * 匹配零次或多次 + 匹配一次或多次 ? 匹配零次或一次 {3} 匹配三次 {3,5} 匹配三到五次 {3,} 匹配三次或以上 下面通过实例了解限定符的区别。 es 的匹配结果 expression e