#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
}
Consider the example, the results of the example are out of my understanding about some relevant rules.
For A b = std::move(a);, it's ill-formed, because it violates the following rule, that is:
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.
That means, a lvalue reference to const volatile-qualified T cannot bind to any rvalue even though they're reference-compatible. A b = std::move(a); obviously violates this rule, hence it's ill-formed.
However I don't know why compile std::move(a).show();without reporting wrong. According to this rule:
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
The type of the implicit object parameter of member function show will be volatile const A& . In general, it definitely violates [dcl.init.ref#5.2]. If change the definition of member function show to:
void show() volatile const& {
}
std::move(a).show(); will be ill-formed. So must be some magic in the following rule that make std::move(a).show(); be compiled before changing show. The rule is:
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.
Honestly, I really don't know what does the wording "in all other respects" mean? And what does the "the type of the implicit object parameter" refer to? Does the "type" refer to volatile const A& or the referenced type volatile const A? The wording is very vague. Anyhow, lvalue reference to const volatile T cannot bind to any rvalue of type T. So, how to interpret that?
As a contrast:
#include <iostream>
struct B{
void show(){}
};
int main(){
volatile B b;
std::move(b).show(); //ill-formed
}
the type of the implicit object parameter of show would be B&, According to [over.match.funcs#general-5], even though ignore const-qualifier, it's still ill-formed due to it discards the volatile-qualifier. From this example, it implies that, For this sentence "in all other respects the argument can be converted to the type of the implicit object parameter", where the type should refer to reference type rather than the type the reference refers to. If the magic is this, it's still not sufficient to make std::move(a).show(); to be well-formed.
So, how to interpret these issues? I don't know how to use [over.match.funcs#general-5] to interpret these two examples.