Агрегатная/назначенная инициализация структуры С++: ссылка непосредственно на другое поле

При использовании агрегатной/назначенной инициализации структуры можно ссылаться на другое поле следующим образом:

#include <stdio.h>


int main()
{
  struct
  {
    int a;
    int b;
  }
  s = 
  {
    .a = 3,
    .b = s.a + 1,
  };

  return 0;
}

Мы используем s.a при инициализации s.b. Однако нам нужно обратиться к s.a через s. Можно ли напрямую ссылаться на s.a. просто как .a или подобное? Это, например, позволит использовать тот же синтаксис при инициализации массивов структур, как здесь:

int main()
{
  struct
  {
    int a;
    int b;
  }
  s[] = 
  {
    {
      .a = 3,
      .b = s[0].a + 1,
    },
    {
      .a = 5,
      .b = s[1].a - 1,
    }
  };

  return 0;
}

Здесь мы могли бы написать что-то вроде .b = .a - 1 вместо .b = s[1].a - 1.


person Sara Haugen    schedule 12.11.2020    source источник
comment
Даже если бы вы могли напрямую ссылаться на элемент в инициализирующем выражении, как это помогло бы в случае с массивом? Учитывая .b = .a - 1, как бы вы различили .b = s[0].a - 1 и .b = s[1].a - 1?   -  person cigien    schedule 12.11.2020
comment
@cigien Их можно было бы различать по области видимости, например, если бы .a была обычной переменной.   -  person Sara Haugen    schedule 12.11.2020
comment
Хорошо, допустим, это сработало, будет ли .a относиться к s[0].a или s[1].a? Оба находятся в одной области.   -  person cigien    schedule 12.11.2020
comment
@cigien Если бы инициализаторы фигурных скобок для каждой структуры рассматривались как область, то они были бы в разных областях. Конечно, это, вероятно, теоретическое обсуждение, поскольку оно, похоже, так не работает.   -  person Sara Haugen    schedule 12.11.2020
comment
Действительно, это так не работает, но с теорией все в порядке :) Теперь я вижу, что вы хотите, чтобы код делал, я неправильно понял это. И да, это разумно ожидать от кода, за исключением правил, запрещающих это: p   -  person cigien    schedule 12.11.2020


Ответы (1)


Можно ли напрямую ссылаться на s.a просто как на .a или что-то подобное?

Нет, .a в этом контексте является обозначением, и на него нельзя ссылаться в обозначающем скобках-или-равном-инициализаторе, используемом для инициализации данного члена данных с помощью его соответствующий указатель.

struct Bar { int a; };

struct Foo {
    int a;
    Bar b;
};

int main() {
    Foo f = {
     //     ^ start of braced-init-list
        .a
     // ^^ designator (for data member of Foo)
            = 1,
     //     ^^^ initializer-clause
        .b{.a = 2}
     //   ^^^^^^^^ braced-init-list
     //   referring to a designator of a 
     //   data member of Bar
    };
}

Подробности

Назначенные инициализаторы, новая функция C++20, представленная P0329R4, являются частью грамматика для списков инициализации в фигурных скобках:

braced-init-list:
  { initializer-list ,opt }
  { designated-initializer-list ,opt }
  { }

где грамматика назначенного-инициализатора -list:

designated-initializer-list:
  designated-initializer-clause
  designated-initializer-list , designated-initializer-clause

и, где грамматика для отдельных предложение-инициализатора:s:

designated-initializer-clause:
  designator brace-or-equal-initializer

и где, наконец, обозначение< /а> это:

designator:
  . identifier

Теперь скобка- or-equal-initializer никоим образом не позволяет ссылаться на другой указатель того же объекта. Обратите внимание на разницу между обозначениями и другими идентификаторами, например. обращение к членам данных структуры как части предложения-инициализатора или вложенных списков_инициализации:s в brace-or-equal-initializer< /эм>.

person dfrib    schedule 12.11.2020