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

С++ дает странную ошибку при инициализации структуры с помощью массива внутри

Я пытаюсь скомпилировать очень простой код:

struct T {
    int a[3];
    int b;
    int c;
};

int main() {
    const int as[3] = { 5, 6, 7, };
    const T t {
        as, 2, 3,
    };
    return 0;
}

Но это дает мне очень странные ошибки:

t.cpp: In function 'int main()':
t.cpp:11:5: error: array must be initialized with a brace-enclosed initializer
     };
     ^

Как я понимаю, компилятор хочет, чтобы я инициализировал все в одном месте. Как инициализировать поля отдельно, а затем использовать их во время инициализации структуры позже?

4b9b3361

Ответ 1

Массивы не являются копируемыми и не подлежащими копированию. Если у вас есть доступ к С++ 11 и новее, вы можете использовать std::array.

#include <array>

struct T {
    std::array<int, 3> a;
    int b;
    int c;
};

int main() {
    const std::array<int,3> as = { 5, 6, 7, };
    const T t {
        as, 2, 3,
    };
    return 0;
}

В противном случае вам придется перевернуть петлю и скопировать элементы по отдельности.

Ответ 2

С++ массивы не копируются, поэтому компиляция завершится неудачно. Тем не менее,

struct T {
    int a[3];
    int b;
    int c;
};

int main() {
    const T t {
        {5, 6, 7, }, 2, 3,
    };
    return 0;
}

является альтернативой, хотя он отбрасывает явную переменную as.

Ссылка: http://en.cppreference.com/w/cpp/concept/CopyConstructible

Ответ 3

Как я понимаю, компилятор хочет, чтобы я инициализировал все в одном месте.

Это связано с тем, что типы массивов распадаются на типы указателей, а затем компилятор пытается назначить указатель на тип массива.

Как инициализировать поля отдельно, а затем использовать их во время инициализации структуры позже?

В структуре можно использовать типы указателей (о которых я бы не советовал). Или вы можете использовать классы контейнеров вместо этого (STL).

Ответ 4

Вы также можете сделать это, но при этом предполагается, что ваши данные T t не являются действительно константными, так как я удаляю их константу с помощью const_cast<>()

#include <cstdio>
#include <cstring>
#include <algorithm>

struct T {
    int a[3];
    int b;
    int c;
};

int main() {
    const int as[3] = { 5, 6, 7, };

    const T t {
        {0}, 2, 3,
    };

    memcpy( reinterpret_cast< void* >( const_cast< int* > ( t.a ) ), 
            reinterpret_cast< const void* >( as ), 
            std::min( sizeof t.a, sizeof as ) );

    printf( "t.a: '%d, %d, %d'\n", t.a[0], t.a[1], t.a[2] );
    return 0;
}

Если ваши данные T t на самом деле не постоянны, вы можете сделать это без const_cast<>()

#include <cstdio>
#include <cstring>
#include <algorithm>

struct T {
    int a[3];
    int b;
    int c;
};

int main() {
    const int as[3] = { 5, 6, 7, };

    T t {
        {0}, 2, 3,
    };

    memcpy( reinterpret_cast< void* >( t.a ),
            reinterpret_cast< const void* >( as ), 
            std::min( sizeof t.a, sizeof as ) );

    printf( "t.a: '%d, %d, %d'\n", t.a[0], t.a[1], t.a[2] );
    return 0;
}

Я добавляю reinterpret_cast<>(), потому что memcpy() требует void*

function void * memcpy ( void * destination, const void * source, size_t num );

Копирует значения num байтов из местоположения, на которое указывает источник, непосредственно в блок памяти, на который указывает место назначения. http://www.cplusplus.com/reference/cstring/memcpy/

Я также делаю std::min( sizeof t.a, sizeof as ), чтобы избежать переопределения любых данных, которые не следует делать в случае, если исходный массив намного больше, чем ожидалось.

И, наконец, {0} инициализирует массив по умолчанию нулями. Это также может быть {}, чтобы ничего не инициализировать и позволить значениями по умолчанию быть мусорной памятью/случайными данными.

Ссылки:

  1. Когда следует использовать static_cast, dynamic_cast, const_cast и reinterpret_cast?
  2. Должен ли я использовать static_cast или reinterpret_cast при приведении void * к чему-либо
  3. Когда использовать reinterpret_cast?
  4. Должен ли я использовать C++ reinterpret_cast поверх приведения в стиле C?
  5. Использование функций min и max в C++