Приведение указателя функции к указанному указателю функции noexcept

Скажем, у меня есть эти объявления:

using fp_type = void(*)();
using fp2_type = void(*)() noexcept;

а также

void func(){}
fp_type fp(func);

Актерский состав fp2_type(fp) хорошо сформирован? Наоборот (преобразование указателя функции с указанием noexcept в указатель функции без спецификатора noexcept)?


person user1095108    schedule 22.02.2016    source источник
comment
Наоборот, это нормально и на самом деле является неявным преобразованием. fp2_type(fp) похоже, что это должно быть reinterpret_cast.   -  person T.C.    schedule 22.02.2016
comment
Интересный вопрос. Примечание: 15.4.12 Спецификация исключения не считается частью типа функции   -  person Tomasz Sodzawiczny    schedule 22.02.2016
comment
На самом деле, это до или после того, как они сделали спецификацию исключений частью системы типов (т.е. это для C++1z или C++14/ранее)?   -  person T.C.    schedule 22.02.2016
comment
Я задал очень похожий вопрос о С++ 17 здесь: c17" title="как статический указатель функции бросания на noexcept в c17"> stackoverflow.com/questions/57596276/   -  person Filipp    schedule 23.08.2019


Ответы (1)


Это неправильно сформировано в С++ 14 и более ранних версиях:

using fp2_type = void(*)() noexcept;

из-за N4140 [кроме спецификации]/2:

Спецификация-исключения не должна появляться в объявлении typedef или объявлении-алиаса.

Итак, я собираюсь предположить, что вопрос касается C++1z, где спецификация исключений является частью системы типов.


[conv.fctptr]/1:

Значение prvalue типа «указатель на функцию noexcept» может быть преобразовано в значение prvalue типа «указатель на функцию». Результатом является указатель на функцию.

Таким образом, void (*)() noexcept может быть (неявно) преобразовано в void (*)().

[expr.static.cast]/7:

Инверсия любой стандартной последовательности преобразования (пункт [conv]), не содержащей [(другие случаи опущены)] преобразования указателя на функцию ([conv.fctptr]), может быть выполнена явно с помощью static_cast.

Ничто другое в [expr.static.cast] также не позволяет преобразовать void (*)() в void (*)() noexcept, поэтому это преобразование не может быть выполнено static_cast.

[expr.reinterpret.cast]/6:

Указатель функции может быть явно преобразован в указатель функции другого типа. Эффект вызова функции через указатель на тип функции ([dcl.fct]), который не совпадает с типом, используемым в определении функции, не определен. За исключением того, что преобразование prvalue типа «указатель на T1» в тип «указатель на T2» (где T1 и T2 являются типами функций) и обратно к его исходному типу дает исходное значение указателя, результат такого преобразования указателя не указан. . [Примечание: см. также [conv.ptr] для более подробной информации о преобразовании указателя. — примечание в конце]

Таким образом, reinterpret_cast может выполнить это преобразование.

Поскольку fp2_type(fp) эквивалентно приведению (fp2_type) fp в стиле C ([expr.type.conv]/ 1), и поскольку приведения в стиле C выполняют reinterpret_cast, когда static_cast не возможно (для простоты игнорируя const_cast, так как здесь это не имеет значения), fp2_type(fp) — это правильно сформированное reinterpret_cast. Однако результат такого приведения нельзя использовать, кроме как отбросить обратно.

person T.C.    schedule 22.02.2016
comment
Связанный с этим вопрос: если вы можете преобразовать функцию noexcept в обычную, можете ли вы сделать то же самое (или наоборот) с указателями функций-членов const и volatile? - person dascandy; 22.02.2016
comment
Существует обходной путь для проблемы приведения в С++ 11/14. Объявите функцию со спецификатором noexcept, например, void f() noexcept; затем введите decltype(&f)(fp). Может быть, добавить это в свой ответ? - person user1095108; 22.02.2016