c++castingtype-conversionimplicit-conversion

Is there a way to cast when passing arguments to a function that wants a pointer?


Take the following (common) scenario when dealing with, for example, OpenGL:

You have void glUseProgram(GLuint program);, as well as a host of other functions that all take a GLuint; but there is no glGetUint, you're stuck with glGetInteger.

So, say you have

class Foo() {
public:
    Foo::Foo() {
        glGetIntegerv(GL_CURRENT_PROGRAM, &program);
    }

private:
    GLuint program;
    void Bar();
};

For literally over 10 years in our project, we've had a similar bit of code and only now, without really changing configuration, the compiler has begun complaining about this particular conversion:

error: implicit conversion changes signedness: 'GLint' (aka 'int') to 'GLuint' (aka 'unsigned int') [-Werror,-Wsign-conversion] 

The fix is obviously simple:

class Foo() {
public:
    Foo::Foo() {
        int _program;
        glGetIntegerv(GL_CURRENT_PROGRAM, &_program);
        program = static_cast<GLuint>(_program);
    }

private:
    GLuint program;
    void Bar();
};

But the question is, can I do the same in just one step, without having to use a locally-scoped int in the middle of it?


Solution

  • Is there a way to cast when passing arguments to a function that wants a pointer?

    I think it is not possible (at least not with a cast).

    The problem is that glGetIntegerv expects a pointer to a signed GLint (usually an alias for int), whereas program is an unsigned integer.

    Theoretically you could get rid of the intermediate int _program, by using a cast in the call, something like:

    glGetIntegerv(GL_CURRENT_PROGRAM, static_cast<GLint*>(&program));
    

    But this will not work (as @TedLyngmo demonstrated in a comment below) because you cannot static_cast from unsigned* to int*. reinterpret_cast can do the job but I would stay away from it as much as possible to avoid UB pitfalls.

    Bottom line:
    I think your approach using an intermediate variable is a good solution.
    However - I would make _program a GLint to match the API properly (although it is usually an alias for int anyway).