Преобразование ссылки в функцию
Мне интересно, почему следующий код является правильным:
void foo(){}
void foo2(void(*)()){};
void foo3(void(*)()&){};
int main(){
foo; // type void(&)() lvalue
foo2(foo); // void(&)() -> void(*)() function to pointer conversion
foo3(foo); // ?? conversion
}
Согласно function to pointer
преобразование здесь
Значение типа T может быть преобразовано в значение типа "указатель на T". Результатом является указатель на функцию.
Преобразование хорошо из void (&) () в void (*) (), но не void(*)()&.
В чем причина того, что этот фрагмент кода (особенно строка с??) является правильным?
1 ответ
Параметр foo3
который void(*)()&
на самом деле это указатель на функцию с квалификатором ref. Это не разрешено стандартом.
Проект стандарта C++17 n4659 гласит:
Тип функции с cv-qualifier-seq или ref-qualifier (включая тип с именем typedef-name) должен отображаться только как:
(6.1) - тип функции для нестатической функции-члена,
(6.2) - тип функции, к которой относится указатель на член,
(6.3) - тип функции верхнего уровня объявления typedef функции или объявления псевдонима,
(6.4) - идентификатор типа в аргументе по умолчанию для параметра типа, или
(6.5) - идентификатор типа аргумента шаблона для параметра типа.
Параметр foo3
не соответствует ни одному из указанных выше критериев. Наиболее близким к тому, что вы пытаетесь сделать, является (6.2).
Таким образом, вы можете иметь это вместо этого:
void foo(){}
class C {
public:
void foo1() & {}
};
void foo2(void(*)()){};
void foo3(void(C::*)()&){};
int main(){
(void) foo;
foo2(foo);
foo3(&C::foo1);
}
Это компилируется как в GCC, так и в Clang. Демо здесь.