Я проверил следующий код с GCC, Clang, ICC и VS:
void f() {}
void g(void (&&)()) { }
int main() {
g(f);
}
Как мы видим, g
принимает ссылку rvalue, но f
является lvalue и, вообще говоря, ссылки rvalue не могут быть привязаны к lvalues. Именно о том, что ICC жалуется о:
error: an rvalue reference cannot be bound to an lvalue
VS также дает ошибку, но по другой причине:
error C2664: 'void h(void (__cdecl &&)(void))' : cannot convert parameter 1 from 'void (__cdecl *)(void)' to 'void (__cdecl &&)(void)'
Это говорит мне, что VS немедленно выполняет преобразование от функции к указателю, а не напрямую связывает ссылку с f
. Стоит отметить, что если я заменил g(f)
на g(&f)
, то четыре компилятора произведут ту же самую ошибку.
Наконец, GCC и Clang принимают код, и я считаю, что они верны. Мои рассуждения основаны на 8.5.3/5
Ссылка на тип "cv1 T1" инициализируется выражением типа "cv2 T2" как
- Если ссылка является ссылкой lvalue [...]
- В противном случае [...] ссылка должна быть ссылкой rvalue.
- Если выражение инициализатора является [...] функцией lvalue [...]
то ссылка привязана к значению выражения инициализатора [...]
Является ли моя интерпретация правильной (то есть, Clang и GCC совместимы по данной причине)?