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

Существуют ли языковые конструкции, которые действительны для имени типа, но не для базовых типов?

Я заметил, что вызов псевдо-деструктора действителен, когда используется имя типа, но не при использовании базового типа.

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

Объяснение вышесказанного можно найти в ответе на другое сообщение SO.

Определение типа-имени из стандарта С++ 11:

7.1.6.2 Спецификаторы простого типа, p1

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

Существуют ли какие-либо другие языковые конструкции, которые действительны, когда спецификатор типа является именем типа, но не является допустимым, если он является фундаментальным типом, даже если имя типа представляет собой фундаментальный тип, как показано выше?

4b9b3361

Ответ 1

Я не думаю, что вы найдете другие случаи. Если мы рассмотрим проект стандарта С++ в приложении A Grammar summary, мы увидим только другие места в грамматике, где отображаются имена типов:

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

и

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

Ни один из них не дает аналогичной возможности, которую мы получаем с pseduo-destructor, который имеет следующую грамматику:

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 

и рассматривается в разделе 5.2.4 [expr.pseudo], который обеспечивает поведение, которое мы видим:

Использование псевдо-деструктора-имени после точки. или стрелка → представляет деструктор для типа некласса, обозначаемого типом или спецификатор decltype. Результат должен использоваться только как операнд для оператора вызова функции(), и результат такого вызова имеет тип void. Единственный эффект - это оценка постфиксного выражения перед точкой или стрелкой.

С другой стороны, мы можем видеть, что правила для вложенного имени-спецификатора в разделе 3.4.3 [basic.lookup.qual] запрещают такой случай:

Название члена класса или пространства имен или перечислителя может быть передано после того, как оператор разрешения области (5.1), примененный к nested-name-specifier, который обозначает его класс, пространство имен или перечисление. Если оператор разрешения области:: scope Вложенному имени-спецификатору не предшествует спецификатор decltype-specifier, lookup названия, предшествующего этому: рассматривает только пространства имен, типы и шаблоны, специализация которых - типы. Если имя не найдено укажите пространство имен или класс, перечисление или зависимый тип, программа плохо сформирована

Случай простого типа-спецификатора не приводит нас туда, поскольку фундаментальные типы уже приемлемы для этого случая.

Ответ 2

Существует разница, когда возвращаемый тип функции является фундаментальным типом или нет:

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;
}

Без шаблонов, чтобы быть еще более ясным:

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;
}

r значения для фундаментальных типов не могут быть изменены. Это явно не относится к другим типам, так как, например, операция перемещения должна изменять временное перемещение (например, сделать указатель владельца nullptr)