Назначение подмассива: инициализация с "{...}" ожидается для ошибки агрегированного объекта

Какое хорошее объяснение ошибки в строке 1?

/* Line 0 */    int foo[10][10];
/* Line 1 */    int foo_alias_compile_error[] = foo[0];
/* Line 2 */    int foo_alias_also_errors[10] = foo[0];
/* Line 3 */    int * foo_alias_works = foo[0];

Ошибка в строке 2 меня особо не беспокоит, потому что мне не нужно повторяться и повторно объявлять размер массива. Однако ошибка в строке 1 (инициализация с "{...}", ожидаемая для агрегатного объекта) меня смущает. Я понимаю, что int foo_alias_compile_error[], вероятно, является «агрегированным объектом». Я просто не понимаю, почему язык настроен так, чтобы он не работал. Я понимаю, почему работает строка 3, но она кажется нерепрезентативной — это массив, поэтому я бы предпочел самодокументировать его как массив.

Вместо этого вы можете использовать std::array<std::array<int, 10>, 10>. Он самодокументируется, как вы хотите, и ведет себя так, как вы ожидаете, как и другие типы значений.

François Andrieux 29.05.2019 22:15

Ах, это хороший момент. К сожалению, это на графическом процессоре, поэтому ни одна из STL мне недоступна.

interestedparty333 29.05.2019 22:15

Обратите внимание, что в строке 3 содержится указатель на foo[0], а это не то, что вам нужно от строки 1. Похоже, вы намереваетесь сделать копию этого массива. Если это так, то линия 3 будет вести себя совсем по-другому.

François Andrieux 29.05.2019 22:15

Вы должны пометить вопрос любым языком шейдеров, который вы используете. Это не вопрос C++, даже если многие языки шейдеров очень похожи на C++.

François Andrieux 29.05.2019 22:17

Возможный дубликат Присвоение одного массива другому массиву С++

Fabio says Reinstate Monica 29.05.2019 22:22

спасибо @fabioturati Вот более длинная версия этого stackoverflow.com/questions/4810664/…

interestedparty333 29.05.2019 22:23

@ François Andrieux Я думаю, вы имеете в виду, что я случайно вызываю оператор копирования для массива, что не входило в мои намерения. Я вижу, как может иметь смысл семантика «копировать объект/массив». Придется читать дальше.

interestedparty333 29.05.2019 22:25

Упрощенный пример: int arr[5]; int arr2[5] = arr; <- ошибка. Вы не можете копировать массивы в C или C++.

SergeyA 29.05.2019 22:27

@FrançoisAndrieux выглядит как действительный код C++ (несмотря на ошибку компиляции) для меня?

SergeyA 29.05.2019 22:28

@ragerdl Если вам просто нужна ссылка на массив, вам нужна int (&bar)[10] = foo[0];. Здесь bar — ссылка на int[10], инициализированная массивом foo[0].

François Andrieux 29.05.2019 22:28

@formerlyknownas_463035818 нет, ваш пример другой.

SergeyA 29.05.2019 22:29

@SergeyA Да, но ОП говорит, что они не могут использовать все функции языка, потому что они будут запускать код на графическом процессоре. Обычно это означает, что это шейдер, код которого очень похож на C и C++. Если это так, тег C++ вводит в заблуждение, и было бы важно пометить фактический используемый язык.

François Andrieux 29.05.2019 22:29

@SergeyA Я запутался, о какой ошибке на самом деле идет речь. мой пример был для строки 2

463035818_is_not_a_number 29.05.2019 22:30

@FrançoisAndrieux, о, это в комментариях, я пропустил.

SergeyA 29.05.2019 22:31

@formerlyknownas_463035818 по-прежнему нет, потому что foo[0] — это массив, а 0 в вашем случае — нет.

SergeyA 29.05.2019 22:32

@SergeyA Мех, мое замешательство было еще хуже, извините, я выпью пива, ура :P

463035818_is_not_a_number 29.05.2019 22:32

Спасибо всем! Я включил отзыв в ответ. Я также включил объяснение об источнике моего замешательства в этом ответе. Спасибо еще раз!

interestedparty333 29.05.2019 22:53
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
17
295
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

когда вы не указываете размер массива (в строке 1). компилятор указывает это для вас. а для этого надо сделать так:

/* Line 0 */    int foo[10][10];
/* Line 1 */    int foo_alias_compile_error[] = {foo[0]};

но у него все еще есть проблема. при компиляции этого кода:

 $ g++ error.cpp
 $ error.cpp:4:28: error: invalid conversion from ‘int*’ to ‘int’ [-fpermissive]
 $    4 |     int fooError[] = {foo[0]};
 $      |                       ~~~~~^
 $      |                            |
 $      |                            int*

потому что foo[0] является указателем и указывает на первую строку вашей матрицы (в строке 1). ты можешь это сделать:

/* Line 0 */    int foo[10][10];
/* Line 1 */    int foo_alias_compile_error[] = {foo[0][0]};
Ответ принят как подходящий

Можно было бы думать о строке 1 как о создании ссылки на 0-ю запись foo. Однако C++ работает иначе. Скорее, оператор присваивания (=) вызывает операцию копирования. Таким образом, C++ интерпретирует строку 1 как директиву для копирования элементов foo[0] в новый массив с неподходящим именем foo_alias_compile_error.

Это не то, что имелось в виду — нужна была ссылка, а не копия. Итак, хорошо, что C++ вызвал ошибку по несвязанной с этим причине и спас ее от самого себя.

Жизнеспособное решение предложено @FrançoisAndrieux. Вот более полный пример, показывающий, что ссылка (не копия) может быть сделана с помощью int (&foo_reference)[10] = foo[0];.

int foo[10][10];
for (int i = 0; i < 10; ++i) {
    for (int j = 0; j < 10; ++j) {
        foo[i][j] = i + j * 10;
    }
}
int (&foo_reference)[10] = foo[0];

for (int j = 0; j < 10; ++j) {
    foo_reference[j] = 100 + j;
}

for (int i = 0; i < 10; ++i) {
    printf("foo   [0][%i] is %i\n", i, foo[0][i]);
    printf("foo_refer[%i] is %i\n", i, foo_reference[i]);
}

Выходной фрагмент

foo   [0][0] is 100
foo_alias[0] is 100
foo   [0][1] is 101
foo_alias[1] is 101
foo   [0][2] is 102
foo_alias[2] is 102
foo   [0][3] is 103
foo_alias[3] is 103

Примечание

Стоит отметить, что функции, принимающие массивы в качестве аргументов, неявно преобразуют свои аргументы-массивы в указатели (как показано в строке 3). Итак, это одна из причин, по которой кто-то может ошибочно подумать, что что-то вроде строки 1 должно работать.

Другими словами, следующий код

void barz(int arg[]) {
    arg[2] = 99999;
}

int another_array[] = {0, 1, 2, 3, 4};
barz(another_array);
printf("another_array[2] is %i\n", another_array[2]);

«Правильно» печатает 99999, а не 2.

Это объясняет проблему, но на самом деле не предлагает решения. Итак, я думаю, я повторю свой комментарий здесь: если вам просто нужна ссылка на массив, вам нужна int (&bar)[10] = foo[0];. Здесь bar — ссылка на int[10], инициализированная массивом foo[0].

François Andrieux 29.05.2019 22:32

Я думаю, вам нужно прочитать хорошую книгу по C++, а не учить язык методом проб и ошибок. Кураторский список можно найти здесь: stackoverflow.com/questions/388242/….

SergeyA 29.05.2019 22:34

@FrançoisAndrieux или даже auto& ref = foo[0];

SergeyA 29.05.2019 22:36

int никогда не называют «псевдонимом», возможно, вам стоит взглянуть на ссылки

463035818_is_not_a_number 29.05.2019 22:36

Аааа, так ты хотел псевдоним! Да, это даже часть имен переменных, но я толком этого не понимал, пока не прочитал это. Затем я второй @FrançoisAndrieux: то, что вы хотите, называется ссылкой, в которой используется &, и вы должны использовать его синтаксис. Боюсь, предложенный мной дубликат указывает, почему вы получаете сообщение об ошибке, но не объясняет, как делать то, что вы хотите. Ну, вы могли бы обновить свой вопрос, дав понять, что вы пытаетесь получить псевдоним!

Fabio says Reinstate Monica 29.05.2019 22:37

Инициализатор в определении массива (то есть массив в стиле C) должен должен быть списком в фигурных скобках.

Это правило распространяется как на вашу строку 1, так и на строку 2, где вы предоставляете что-то, что не является списком в фигурных скобках, и поэтому код неверен.

Дополнительная информация: когда вы предоставляете список в фигурных скобках, каждый элемент списка берется в качестве инициализатора для элемента ан массива. Как следствие, невозможно указать один инициализатор, который приводит к установке им нескольких элементов массива.

Это правило почти применимо рекурсивно; если у вас есть массив массивов, то инициализатор должен быть списком фигурных скобок. Однако есть правило, что в некоторых случаях вложенные фигурные скобки могут быть опущены (и код будет вести себя так, как если бы были предоставлены полные скобки). Например, int x[2][2] = { 1, 2, 3, 4 }; разрешено и ведет себя как int x[2][2] = { {1, 2}, {3, 4} };.

Другие вопросы по теме