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
esttrue
si l’ensemble des exceptions potentielles de l’expression ([except.spec]) est vide etfalse
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’argumentArgTypes
et le type renvoyéR
si l’expressionINVOKE(declval
, considérée comme un opérande non évalué (Clause [expr]), est bien formé ([func.require]).(), declval ()..., R)
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.