hectorhfm
hectorhfm

Reputation: 105

Sizeof() function not working over a constant array C++

Before starting, I am compiling the program using VS2015 C++ language. The problem is a compiling error when I try to determine the size of two constant arrays. Class involved in the issue:

Header file:

#ifndef RACE_H_
#define RACE_H_
class Race
{
    private:
        static const int PILOT_POINTS[];
        static const double TEAM_AWARDS[];
}
#endif

Source file:

#include "Race.h"
const int PILOT_POINTS[] = { 25, 18, 15, 12, 10, 8, 6, 4, 2, 1 };
const double TEAM_AWARDS[] = { 100000, 75000, 50000, 25000, 15000, 10000 };

Part of the errors:

sizeof(TEAM_AWARDS) / sizeof(TEAM_AWARDS[0]))
sizeof(PILOT_POINTS) / sizeof(PILOT_POINTS[0]))

The compiler says:

Error 2070 const int[] operand sizeof not valid.

An incomplete type is not allowed.

Error 2070 const double[] operand sizeof not valid.

An incomplete type is not allowed.

Could I use extern to solve the problem? If so, how should I use it?

Upvotes: 1

Views: 2282

Answers (3)

Hector
Hector

Reputation: 2534

Other answers have addressed the fact that you need to define the array. For the sake of completeness, I would mention that your way of getting the size of the array is "the C version". C++ has a better way std::extent:

#include <iostream>
#include <type_traits>

struct Race
{
    static const int PILOT_POINTS[];
    static const double TEAM_AWARDS[];
};

const int Race::PILOT_POINTS[] = { 25, 18, 15, 12, 10, 8, 6, 4, 2, 1 };
const double Race::TEAM_AWARDS[] = { 100000, 75000, 50000, 25000, 15000, 10000 };

int main()
{
    ::std::wcout << ( sizeof( Race::PILOT_POINTS ) / sizeof( Race::PILOT_POINTS[ 0 ] ) ) << L' '
        << ( sizeof( Race::TEAM_AWARDS ) / sizeof( Race::TEAM_AWARDS[ 0 ] ) ) << L'\n'
        << std::extent< decltype( Race::PILOT_POINTS ) >::value << L' '
        << std::extent< decltype( Race::TEAM_AWARDS ) >::value;
    return 0;
}

Upvotes: 1

George Hilliard
George Hilliard

Reputation: 15942

The problem is that you have declared the arrays, but you have not defined them at the point you are invoking the sizeof operator.

Furthermore, you can't just move your definition to the header, because only integral types may be defined this way:

If a non-volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment- expression is a constant expression. A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression... (§9.4.2/3)

C-style variable length arrays are not integral, because their length isn't known until they are defined.

To solve this problem, you need to use a length-specifier in the array:

#ifndef RACE_H_
#define RACE_H_
class Race
{
    private:
        static const int PILOT_POINTS[10];
        static const double TEAM_AWARDS[6];
}
#endif

This is extra hassle, because now you must change the lengths if the array changes sizes, but it's necessary.

Alternately, you can use constexpr, and put the entire definition in the header. This way, you can omit the array lengths.

#ifndef RACE_H_
#define RACE_H_
class Race
{
    private:
        static constexpr int PILOT_POINTS[]
                = { 25, 18, 15, 12, 10, 8, 6, 4, 2, 1 };
        static constexpr double TEAM_AWARDS[]
                = { 100000, 75000, 50000, 25000, 15000, 10000 };
}
#endif

Also, you might try what @CoryKramer suggests in a comment, and use a vector. You'll have a very small run-time cost to initialize it and to look up the size, but that shouldn't matter much.

Upvotes: 3

Barry
Barry

Reputation: 302718

You need to just provide the size in the declaration. From [dcl.array]:

Except as noted below, if the constant expression is omitted, the type of the identifier of D is “derived-declarator-type-list array of unknown bound of T”, an incomplete object type.

And [expr.sizeof]:

The sizeof operator shall not be applied to an expression that has function or incomplete type [...]

The exceptions for arrays without the constant expression size are when you provide an initializer (e.g. int a[] = {1, 2}) or when the array was previously declared with a size. So in this case, you could either provide the size or the initializer the header:

static const int PILOT_POINTS[10];    
static const int PILOT_POINTS[] = { 25, 18, 15, 12, 10, 8, 6, 4, 2, 1 };

or simply just use a vector, so you can initialize it in the source, and get all the other nice advantages of vector over raw C arrays:

static const std::vector<int> PILOT_POINTS;

Upvotes: 1

Related Questions