Heureusement, le standard a une liste pratique de ceux-ci (§ 5 [expr] ¶ 8):
Dans certains contextes, non évaluée opérandes apparaissent (5.2.8, 5.3.3, 5.3.7, 7.1.6.2). Non évalué opérande n'est pas évalué. Non évalué opérande est considéré comme une pleine expression.
Regardons en détail.
Je vais utiliser les déclarations suivantes dans mes exemples. Les fonctions déclarées ne sont jamais définie n'importe où, alors si un appel apparaît dans un évalués contexte, le programme est mal formé et nous allons obtenir un lien à l'erreur. En les appelant non évalué contexte est très bien, cependant.
int foo(); // never defined anywhere
struct widget
{
virtual ~widget();
static widget& get_instance(); // never defined anywhere
};
typeid
§ 5.2.8 [expr.typeid] ¶ 3:
Lors de l' typeid
est appliquée à une expression autre qu'un glvalue d'un polymorphe type de classe, le résultat fait référence à un std::type_info
objet représentant le type statique de l'expression. Lvalue-à-rvalue (4.1), tableau de pointeur (4.2), et la fonction de pointeur (4.3) les conversions ne sont pas appliquées à l'expression. Si le type de l'expression est un type de classe, la classe doit être complètement défini. L'expression est un opérande non évaluée
(Alinéa 5).
Remarque l'a souligné exception pour polymorphes cours ( class
avec au moins un virtual
membre).
Donc, c'est bien
typeid( foo() )
et donne un std::type_info
objet pour int
alors que ce
typeid( widget::get_instance() )
n'est pas et ne sera probablement produire un lien erreur. Il a à évaluer l'opérande parce que le type dynamique est déterminée par la recherche de la vptr
au moment de l'exécution.
<coup de gueule>je trouve ça assez déroutant que le fait de savoir si ou non le type statique de l'opérande est polymorphe de la sémantique de l'opérateur dans de telles spectaculaires, mais subtile, des moyens.</coup de gueule>
sizeof
§ 5.3.3 [expr.sizeof] ¶ 1:
L' sizeof
opérateur donne le nombre d'octets dans la représentation des objets de son opérande. L'opérande est soit une expression, qui est un non évaluée opérande (Alinéa 5), ou d'une mise entre parenthèses de type id. L' sizeof
exploitant ne doit pas être appliquée à une expression qui a la fonction ou de type incomplète, à un type d'énumération dont le type sous-jacent n'est pas fixe, avant de l'ensemble de ses agents recenseurs ont été déclarés, à la mise entre parenthèses du nom de ces types, ou à un glvalue qui désigne un peu de champ.
La suite
sizeof( foo() )
est parfaitement bien, et équivalente à sizeof(int)
.
sizeof( widget::get_instance() )
est aussi permis. Notez, cependant, que c'est équivalent à sizeof(widget)
et donc sans doute pas très utile sur un polymorphe return
type.
noexcept
§ 5.3.7 [expr.unaire.noexcept] ¶ 1:
L' noexcept
opérateur détermine si l'évaluation de son opérande, ce qui est un non évaluée opérande (Alinéa 5), peut lever une exception (15.1).
L'expression
noexcept( foo() )
est valide et évalue false
.
Voici un exemple plus réaliste exemple qui est aussi valable.
void bar() noexcept(noexcept( widget::get_instance() ));
Notez que seuls les intérieurs noexcept
est l'opérateur tandis que l'extérieur est le spécificateur.
decltype
§ 7.1.6.2 [dcl.type.simple] ¶ 4.4:
L'opérande de l' decltype
spécificateur est un non évaluée opérande (Alinéa 5).
La déclaration
decltype( foo() ) n = 42;
déclare une variable n
de type int
et l'initialise avec la valeur 42.
auto baz() -> decltype( widget::get_instance() );
déclare une fonction baz
qui ne prend pas d'arguments et d' return
s - widget&
.
Et c'est tout ce qu'il y a (comme en C++14).