27 votes

Existe-t-il des constructions linguistiques qui sont valables pour les noms de type mais pas pour les types fondamentaux ?

J'ai remarqué que l'appel au pseudo destructeur est valide lorsqu'un nom du type est utilisé, mais pas lorsqu'un type fondamental est utilisé.

typedef int BType;
int b;
b.~BType();   // Legal
b.~int();     // Not legal

Une explication de ce qui précède peut être trouvée à l'adresse suivante une réponse à un autre message de SO .

Définition de nom du type de la norme C++11 :

7.1.6.2 Spécification de type simple, p1

type-name:
class-name
enum-name
typedef-name
simple-template-id

Existe-t-il d'autres constructions de langage qui sont valides lorsque le spécificateur de type est un nom du type mais non valable lorsqu'il s'agit d'un type fondamental, même si le nom du type représente un type fondamental, comme indiqué ci-dessus ?

4voto

Shafik Yaghmour Points 42198

Je ne pense pas que vous trouverez d'autres cas. Si nous regardons le projet de norme C++ Annexe A Résumé grammatical nous pouvons voir les seuls autres endroits dans la grammaire où nom du type Les spectacles sont :

nested-name-specifier:
  ::
  type-name ::
  namespace-name ::
  decltype-specifier ::
  nested-name-specifier identifier ::
  nested-name-specifier templateopt simple-template-id ::

et :

simple-type-specifier:
  nested-name-specifieropt type-name
  [...]

Aucun des deux ne fournit une opportunité similaire à celle que nous obtenons avec le destructeur pseduo qui a la grammaire suivante :

pseudo-destructor-name:
  nested-name-specifieropt type-name :: ~ type-name
  nested-name-specifier template simple-template-id :: ~ type-name
  nested-name-specifieropt~ type-name
  ~ decltype-specifier 

et est traité dans la section 5.2.4 [expr.pseudo] qui fournit le comportement que nous voyons :

L'utilisation d'un pseudo-destructeur-nom après un point . ou une flèche -> opérateur représente le destructeur pour le type non-classe indiqué par le nom de type ou le spécificateur decltype. Le résultat ne doit être utilisé que comme opérande pour l'opérateur d'appel de fonction (), et le résultat d'un tel appel est de type void. Le seul effet est l'évaluation de l'expression postfixe avant le point ou la flèche.

d'autre part, nous pouvons voir les règles pour les spécificateurs de noms imbriqués dans la section 3.4.3 [basic.lookup.qual] interdit un tel cas :

Le nom d'une classe, d'un membre d'un espace de nom ou d'un énumérateur peut être mentionné après l'opérateur de résolution de portée : : (5.1) appliqué à un spécificateur de nom imbriqué qui désigne sa classe, son espace de noms ou son énumérateur. qui désigne sa classe, son espace de noms ou son énumérateur. énumération. Si un opérateur de résolution : : scope dans un nested-name-specifier n'est pas précédé d'un decltype-specifier, la consultation du nom précédant ce : : ne considère que les espaces de noms, les types et les les modèles dont les spécialisations sont des types. Si le nom trouvé ne désigne pas un espace de noms ou une classe, une énumération ou un type dépendant, le programme est mal formé. est mal formé

Le cas du spécificateur de type simple ne nous y conduit pas non plus puisque les types fondamentaux sont déjà acceptables dans ce cas.

2voto

bolov Points 4005

Il y a une différence lorsque le type de retour d'une fonction est un type fondamental ou non :

struct X{};

template <class T> auto foo() {
  // one liner
  []() -> T { return T{}; }() = T{}; // invalid for T fundamental type

  // or more clear:
  auto get_t = []() -> T { return T{}; };
  get_t() = T{}; // invalid for T fundamental type
}

auto main() -> int {
  foo<X>();    // valid
  foo<int>();  // invalid
  return 0;
}

Sans modèles, pour être encore plus clair :

struct X{};

auto ret_x() -> X { return X{}; }    
auto ret_int() -> int { return int{}; }

auto main() -> int {
  ret_x() = X{};     // valid
  ret_int() = int{}; // invalid
  return 0;
}

Les valeurs r des types fondamentaux ne peuvent pas être modifiées. Ce n'est évidemment pas le cas pour les autres types, car, par exemple, une opération de déplacement doit modifier le temporaire à partir duquel elle est déplacée (par exemple, rendre le pointeur propriétaire nullptr).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X