Comment le système de type spécificateur d’exception C ++ 17 fonctionnera-t-il?

En étudiant “spécificateur noexcept (et opérateur)”, j’ai écrit un code simple. Et je suis surpris que ce morceau de code:

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

affiche false , même la fonction “asdf” est spécifiée par noexcept.

Ainsi, tout en cherchant la raison de ce phénomène mystérieux, j’ai trouvé le “système de type spécificateur d’exception” de C ++ 17 – P0012R1 .

Selon cette proposition (acceptée), depuis C ++ 17; comme noexcept fait partie du type de fonction, le code ci-dessus sera-t-il imprimé true ?

Et un de plus, dans cette ligne de la question:

 std::function f 

La spécification noexcept semble ignorée en C ++ 14 ou 11. Ce code fonctionnera-t-il comme prévu en C ++ 17?

Selon cette proposition (acceptée), depuis C ++ 17; comme noexcept fait partie du type de fonction, le code ci-dessus sera-t-il imprimé true ?

Oui.

Le type de f sera déduit de void(*)() noexcept puisque la conversion de fonction en pointeur appliquée à asdf préservera la propriété noexcept . Un appel à un pointeur de fonction noexcept ne peut certainement pas noexcept une exception, sauf si l’une de ses sous-expressions le fait.

Pour la formulation exacte, voir [expr.unary.noexcept] / 3 et [expect.spec] / 13 . Notez que le nouveau libellé du dernier paragraphe du brouillon C ++ 17 provient de P0012R1, qui est lié dans le PO.

Le résultat de l’opérateur noexcept est true si l’ensemble des exceptions potentielles de l’expression ([except.spec]) est vide et false sinon.

  • Si e est un appel de fonction ([expr.call]):
    • Si son expression postfixe est une expression id (éventuellement) (entre parenthèses) ([expr.prim.id]), un access de membre de classe ([expr.ref]) ou une opération pointeur sur membre ([expr.mptr.oper] ) dont l’ expression cast est une expression id , S est l’ensemble des types de la spécification d’exception de l’entité sélectionnée par l’ expression id contenue (après résolution de la surcharge, le cas échéant). …

Donc, l’ensemble des exceptions potentielles de f() est le même que celui des types de la spécification d’exception de f , qui est vide puisque f est déclaré noexcept .

Passons à la deuxième question:

La spécification noexcept semble ignorée en C ++ 14 ou 11. Ce code fonctionnera-t-il comme prévu en C ++ 17?

Votre question semble être: std::function refusera-t-il de détenir une fonction pouvant générer des exceptions?

Je dirais que ce n’est pas clair. Dans le libellé actuel de la norme, std::function n’est pas défini, tout comme std::function n’est pas défini . Ce n’était évidemment pas un problème en C ++ 14, car noexcept n’était pas considéré comme faisant partie du type d’une fonction.

std::function simplement casser en C ++ 17? C’est incertain pour moi. Jetons un coup d’œil au libellé actuel pour deviner ce que le comportement “devrait” être.

La norme exige que l’argument du constructeur de std::function soit “Lvalue-Callable” pour les types d’argument ArgTypes... et le type de retour R , ce qui signifie :

Un type appelable ([func.def]) F est Lvalue-Callable pour les types d’argument ArgTypes et le type renvoyé R si l’expression INVOKE(declval(), declval()..., R) , considérée comme un opérande non évalué (Clause [expr]), est bien formé ([func.require]).

Peut-être devrait-il y avoir une exigence supplémentaire selon laquelle si le type de fonction est noexcept , alors noexcept(INVOKE(...)) doit également être vrai. Néanmoins, cette formulation n’est pas présente dans le projet actuel.

Dans P0012R1, il y a un commentaire qui:

C’est une question ouverte, comment propager “noexcept” via std::function .

J’imagine qu’ils signifient qu’il n’est pas clair comment std::function pourrait être implémenté si cette exigence supplémentaire était imposée. Espérons que quelqu’un d’autre puisse fournir plus de détails.