#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]来解释这两个例子。
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)可以说有一个更即时的错误消息:
错误:
成员函数
参数是右值,但函数具有非常量左值ref限定符show
的此
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