Что случилось с "строгим правилом псевдонимов" типа агрегирования или объединения, включающего один из вышеупомянутых типов? - PullRequest
2 голосов
/ 04 июля 2019

Раньше в basic.lval существовал этот пункт:

агрегатный или объединенный тип, который включает в себя один из вышеупомянутых типов среди своих элементов или нестатических элементов данных (включая, рекурсивно, элемент или нестатический член данных субагрегата или содержащего объединения),

В текущем проекте оно пропало.

На сайте WG21 имеется некоторая справочная информация: http://www.open -std.org / jtc1 / sc22 / wg21 / docs / documents / 2019 / p1359r0.html # 2051 :

Правила псевдонимов из пункта 7.2.1 [basic.lval] были адаптированы из C с дополнениями для C ++. Однако ряд баллов либо не применяется, либо включается в другие баллы. Например, предоставление для агрегатных типов и типов объединения требуется в C для структурного присваивания, что в C ++ выполняется через конструкторы и операторы присваивания в C ++, а не посредством доступа к полному объекту.

Может кто-нибудь объяснить мне, что это значит? Какое отношение это строгое правило псевдонимов имеет к присваиванию структуры в C?

cppreference говорит об этом правиле:

Эти маркеры описывают ситуации, которые не могут возникнуть в C ++

Я не понимаю, почему это правда. Например,

struct Foo {
    float x;
};

float y;
float z = reinterpret_cast<Foo*>(&y)->x;

Последняя строка, кажется, делает то, что описывает пункт с маркером. Он получает доступ к y (a float) через агрегат, который включает float (member x).

Может кто-нибудь пролить свет на это?

1 Ответ

5 голосов
/ 04 июля 2019

lvalue, которое вы используете для доступа к сохраненному значению y, не *reinterpret_cast<Foo*>(&y), типа Foo, но reinterpret_cast<Foo*>(&y)->x, который имеет тип float.Доступ к float с использованием lvalue типа float - это нормально.В C ++ вы не можете «получить доступ к значению объединения или структуры» (как целое), вы можете получить доступ только к отдельным членам.Обоснование, которое вы цитировали, указывает на разницу между C и C ++:

  struct X { int a, b; };
  struct X v1 = {1, 2}, v2;
  v2 = v1;

В стандарте C в стандарте говорится, что присвоение загружает значение v1 (как целое), чтобы присвоить его v2.Здесь к значениям объектов v1.a и v2.b (оба имеют типы int) обращаются с использованием lvalue типа struct X (который не int).

В C ++ стандарт говорит, что присваивание вызывает сгенерированный компилятором оператор присваивания, который эквивалентен

struct X {
   ...
   struct X& operator=(const struct X&other)
   {
       a = other.a;
       b = other.b;
   }
};

В этом случае вызов , оператор присваивания не имеет доступа к какому-либо значению,потому что RHS передается по ссылке.И выполнение оператора присваивания получает доступ к двум полям int по отдельности (что нормально, даже без правила агрегирования), так что это снова не позволяет получить доступ к значению через lvalue типа struct X.

...