Can I cause a compile error on “too few initialize

2019-07-04 02:43发布

问题:

I am using an aggregate initializer to set up a block of static data for a unit test.

I would like to use the array size as the expected number of elements, but this can fail if too few initializers are provided:

my_struct_type expected[14] =
{
    { 1.234, 0, 'c' },
    { 3.141, 1, 'z' },
    { 2.718, 0, 'a' }
};

This gives no compiler error in Visual Studio 2008.

I would like to be able to use it as such:

const unsigned expected_size = sizeof(expected) / sizeof(my_struct_type);

BOOST_CHECK_EQUAL(points.size(), expected_size);

for( int i = 0; i < expected_size; i++ )
{
    BOOST_CHECK_EQUAL(points[i].value, expected[i].value);
    BOOST_CHECK_EQUAL(points[i].count, expected[i].count);
    BOOST_CHECK_EQUAL(points[i].sym,   expected[i].sym);
}

but because I don't have a compile-time guarantee of 14 points, this runs off the end of the array end of the provided values and into the default-initialized values.

Can I somehow enforce the number of aggregate array initializers at compile-time?

回答1:

First: There might be a warning for this. Have you tried compiling at the highest warning level?

Then: If you swap which value is calculated and which is literal, you could raise a compile-time error:

my_struct_type my_array[] = // <== note the empty []
{
    { 1.234, 0, 'c' },
    { 3.141, 1, 'z' },
    { 2.718, 0, 'a' }
};

BOOST_STATIC_ASSERT( sizeof(my_array)/sizeof(my_array[0]) == 14 );


回答2:

Actually it won't run off the end of the array, because the compiler will default-initialize all the elements of the array that you didn't initialize yourself.

If you're trying to make sure that you have a specific number of configured initializers, I'm not sure how to do that.

If you just want to make sure the array is the number of items you have:

my_struct_type expected[] =
{
    { 1.234, 0, 'c' },
    { 3.141, 1, 'z' },
    { 2.718, 0, 'a' }
};

Will do the trick. Then just use sizeof(expected) / sizeof(expected[0]) to get the total number of array elements.



回答3:

Just for the sake of a non-Boost answer…

You can add an initialization requirement by modifying my_struct_type.

template< typename T >
struct must_be_initialized {
    T value;

    must_be_initialized( T const &v ) : value( v ) {}
     // no default constructor!

    operator T& () { return value; }
    operator T const& () const { return value; }
};

struct my_struct_type {
    must_be_initialized< double > f;
    int i;
    char c;
};

my_struct_type expected[14] =
{
    { 1.234, 0, 'c' },
    { 3.141, 1, 'z' },
    { 2.718, 0, 'a' }
     // error: no default constructor exists
};

my_struct_type is still an aggregate, but it is not POD.



回答4:

ISO/IEC 14882 (First edition 1998-09-01) in p. 8.5.1.7 states the following:

If there are fewer initializers in the list than there are members in the aggregate, then each member not explicitly initialized shall be default-initialized (8.5). [Example: struct S { int a; char* b; int c; }; S ss = { 1, "asdf" }; initializes ss.a with 1, ss.b with "asdf", and ss.c with the value of an expression of the form int(), that is, 0. ]

Simply, the answer to your question is no.



回答5:

According to the msdn, if fewer initializers are specified, the remaining elements are initialized with 0, so the code should work nonetheless.