15

I try to compile very simple code:

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

But it gives me very strange errors:

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

As from what I understand the compiler wants me to initialize everything in one single place. How do I initialize fields separately and then use them during initiliazation the structure later?

VP.
  • 15,509
  • 17
  • 91
  • 161
  • 4
    `std::array` to the rescue. – DeiDei Sep 14 '17 at 06:52
  • 3
    You can't do that with plain arrays. Are you allowed to modify `T`? – juanchopanza Sep 14 '17 at 06:53
  • @juanchopanza I would like to have only `costs` as possible in my code and to avoid mutation only for initialization of the object, this is my principle.. So The question here is to initialize a const object. – VP. Sep 14 '17 at 06:53
  • 3
    @VictorPolevoy I think that what juanchopanza is asking is if you can change the member `a` ot the structure `T` to be of a different type? For example `std::array a;`? – Some programmer dude Sep 14 '17 at 06:55
  • @Someprogrammerdude Oh, excuse me then. Yes, I can change it to everything, this is my own structure. – VP. Sep 14 '17 at 06:56
  • As a side note, the C solution would be to put the initializer list inside a macro, then use that macro during initialization. Not really something I'd recommend in C++ (since you would be using std::array instead). – Lundin Sep 14 '17 at 14:31

4 Answers4

22

Arrays are neither copy-constructible nor copy-assignable. If you have access to C++11 and newer, you could use 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;
}

Otherwise you will have to roll a loop and copy the elements individually.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
DeiDei
  • 10,205
  • 6
  • 55
  • 80
11

C++ arrays are not copy constructible, so compilation will fail. However,

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

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

is an alternative, although it does discard the explicit as variable.

Reference: http://en.cppreference.com/w/cpp/concept/CopyConstructible

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
2

As from what I understand the compiler wants me to initialize everything in one single place.

This is because array types decay into pointer types and then the compiler tries to assign a pointer to an array type.

How do I initialize fields separately and then use them during initiliazation the structure later?

You can use pointer types in the structure (which I would not advise). Or you can use container classes instead (STL).

dgrat
  • 2,214
  • 4
  • 24
  • 46
0

You can also do this, but it assumes your T t data is not really const as I remove its constness with 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;
}

If you data T t is not actually const, you can do it without the 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;
}

I am adding the reinterpret_cast<>() because memcpy() requires a void*

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

Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination. http://www.cplusplus.com/reference/cstring/memcpy/

I am also doing std::min( sizeof t.a, sizeof as ) to avoid override any data it should not in case the source array is way bigger than expected.

And finally, {0} is initializing by default the destine array with zeros. It could also be {} to not initialize anything and let the default values to be trash memory/random data.

References:

  1. When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?
  2. Should I use static_cast or reinterpret_cast when casting a void* to whatever
  3. When to use reinterpret_cast?
  4. Should I use a C++ reinterpret_cast over a C-style cast?
  5. Use of min and max functions in C++
Evandro Coan
  • 8,560
  • 11
  • 83
  • 144