Преобразование ссылки в функцию

Мне интересно, почему следующий код является правильным:

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 гласит:

[dcl.fct] / 6

Тип функции с 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. Демо здесь.

Другие вопросы по тегам