Подтвердить что ты не робот

Как будет работать система типов спецификаторов исключений С++ 17?

Изучая "noexcept specifier (и operator)", я написал простой код. И я удивлен, что этот фрагмент кода:

void asdf() noexcept {}
int main() 
{
    auto f = asdf;
    std::cout << std::boolalpha << noexcept(f()) << std::endl;
}

печатает false, даже функция "asdf" не указана.

Итак, во время поиска, почему это таинственное явление происходит, я нашел С++ 17 "система спецификатора исключений" - P0012R1.

В соответствии с этим (принятым) предложением, поскольку С++ 17; поскольку noexcept является частью типа функции, будет ли вышеприведенный код true?

И еще один, в этом задайте одну строку:

std::function<void() noexcept> f

Указание noexcept кажется проигнорированным в С++ 14 или 11. Будет ли этот код работать по назначению на С++ 17?

4b9b3361

Ответ 1

В соответствии с этим (принятым) предложением, поскольку С++ 17; поскольку noexcept является частью типа функции, будет ли код выше печатать true?

Да.

Тип f будет выведен на void(*)() noexcept, поскольку преобразование функции в указатель, примененное к asdf, сохранит свойство noexcept. Вызов указателя функции noexcept, безусловно, не может генерировать исключение, если только одно из его подвыражений не делает.

Для точной формулировки см. [expr.unary.noexcept]/3 и [expect.spec]/13. Обратите внимание, что новая формулировка в последнем абзаце из проекта С++ 17 исходит из P0012R1, которая связана в OP.

Результатом оператора noexcept является true, если набор потенциальных исключений выражения ([except.spec]) пуст, а false в противном случае.

...

  • Если e - вызов функции ([expr.call]):
    • Если его постфиксное выражение является (возможно, в скобках) id-выражением ([expr.prim.id]), доступом к члену класса ([expr.ref]) или операцией указателя на член ([expr.mptr.oper]), выражение-выражение которого является id-выражением, S - это набор типов в спецификации исключения объекта, выбранного содержащимся в нем идентификатором (после разрешения перегрузки, если применимо)....

Таким образом, набор потенциальных исключений из f() совпадает с набором типов в спецификации исключения f, который пуст, поскольку f объявлен noexcept.

Перейдем к второму вопросу:

Указание noexcept кажется проигнорированным в С++ 14 или 11. Будет ли этот код работать в соответствии с С++ 17?

Кажется, ваш вопрос: будет ли std::function<void() noexcept> отказаться от функции, которая может генерировать исключения?

Я бы сказал, что он неясен. В настоящей редакции стандарта std::function<void() noexcept> на самом деле не определен, так как std::function<double(float) const> не является определены. Это было, конечно, не проблема в С++ 14, так как noexcept не считался частью типа функции.

Будет ли std::function<void() noexcept> просто сломаться на С++ 17? Это неуверенно для меня. Давайте взглянем на текущую формулировку, чтобы угадать, каково должно быть поведение.

Стандарт требует, чтобы аргумент конструктору std::function<R(ArgTypes..)> был "Lvalue-Callable" для типов аргументов ArgTypes... и возвращаемого типа R, который означает:

Вызываемый тип ([func.def]) f является Lvalue-Callable для типов аргументов ArgTypes и возвращает тип R, если выражение INVOKE(declval<F&>(), declval<ArgTypes>()..., R), рассматриваемое как неоцененный операнд (раздел [expr]), хорошо сформирован ([func.require]).

Возможно, должно быть дополнительное требование: если тип функции noexcept, то noexcept(INVOKE(...)) также должен быть истинным. Тем не менее, эта формулировка отсутствует в нынешнем проекте.

В P0012R1 есть комментарий, который:

Открытая проблема заключается в том, как распространять "noexcept" через std::function.

Я предполагаю, что они означают, что неясно, как std::function может быть реализовано, если это дополнительное требование было наложено. Надеюсь, кто-то еще может предоставить более подробную информацию.