views:

64

answers:

3

I setup a class with:

class Example {
    static const float array[3][8];
};

and implemented

inline const float below_center(const float pos) {
    return pos - (size / 2); // size is a const float
}

inline const float above_center(const float pos) {
    return pos + (size / 2);
}

inline const float *set_pos(const float x, const float y) {
    return (float []) {
        below_center(x), below_center(y),
        below_center(x), above_center(y),
        above_center(x), below_center(y),
        above_center(x), above_center(y),
    };
}

const float Example::array[3][8] = {
    set_pos(2.0f, 0.0f),
    set_pos(-1.0f, -1.0f),
    set_pos(1.0f, -1.0f),
};

But when I do this I get an error saying, "'const float*' to 'const float' in initialization". I understand what the error saying, but the hell is it saying 'const float' and how can implement my array with broken down inline functions.

+2  A: 

Your returning of (float[]) {....} is not legal, because the compound literal is going to emit an automatic array, and you are returning a pointer to an automatic array which is destroyed if control flow leaves that function. You get a dangling pointer.

It's also a C99 feature, so your code is really C++/C99 :)


The second problem that the compiler detects at compile time is the array initialization. Here, brace elision applies. Because a const float* cannot initialize a const float[8], the compiler assumes brace elision and tries to initialize the first member of array[0][0..7] using that const float*. This will not work either and that is reflected by the error message.

You are going to have to fill that array yourself at runtime using some sort of loop or you are going to have to specify the initial values in the array initialization similar to how you do it in the return statement.


Since you are using C++ and C99, why not combine the power and use [boost|tr1]::array?

inline const boost::array<float, 8> set_pos(const float x, const float y) {
    return (boost::array<float, 8>) {{
        below_center(x), below_center(y),
        below_center(x), above_center(y),
        above_center(x), below_center(y),
        above_center(x), above_center(y),
    }};
}

const boost::array<boost::array<float, 8>, 3> Example::array = {{
    set_pos(2.0f, 0.0f),
    set_pos(-1.0f, -1.0f),
    set_pos(1.0f, -1.0f),
}};

Beware that the inline semantics between C++ and C99 differ. Better be sure what semantics apply to your program.

Johannes Schaub - litb
In theory, there should be no dangling pointer since it's an inline function. Unless this one of the differences in C++ and C?
kuroutadori
@Kuroutadori no, in theory this call evaluates to a dangling pointer. It's about the semantics that make it a dangling pointer, not about the actual implementation. Whether or not the call is actually inlined is unspecified. And even if it is inlined, the optimizer may assume anything it likes, including initializing the array with garbage, since the code has undefined behavior.
Johannes Schaub - litb
@Johannes Schaub - I see.
kuroutadori
A: 

There's an extrac "," at the end of your initialization of the Example::array[3][8] call. Actually, that declaration is attempting to put an array into one of the entries of that array.

wheaties
+1  A: 

You can't do like that. Use macros:

#define BELOW_CENTER(pos) ((pos) - (size / 2))
#define ABOVE_CENTER(pos) ((pos) + (size / 2))

#define SET_POS(x, y) {               \
    BELOW_CENTER(x), BELOW_CENTER(y), \
    BELOW_CENTER(x), ABOVE_CENTER(y), \
    ABOVE_CENTER(x), BELOW_CENTER(y), \
    ABOVE_CENTER(x), ABOVE_CENTER(y)  \
}

const float Example::array[3][8] = {
    SET_POS(2.0f, 0.0f),
    SET_POS(-1.0f, -1.0f),
    SET_POS(1.0f, -1.0f),
};
adf88
The whole point of using inline is to avoid macros. So what's the point of inline then?
kuroutadori