I have this class with a function that returns a value. For complicated reasons, the value needs to be returned as a const
reference.
(minimal working example contains an int
array, real code has more complex objects, hence the reference)
class Foo
{
public:
static constexpr const int OUT_OF_BOUNDS_VALUE = -9999;
const int& ret(int i) const { return i < 0 || i > 4 ? OUT_OF_BOUNDS_VALUE : test[i]; }
private:
int test[5] = {0, 1, 2, 3, 4};
};
This gives me warning C4172: returning address of local variable or temporary
in VS2015 and it doesn't even compile with GCC.
- Adding the line
constexpr const int Foo::OUT_OF_BOUNDS;
outside ofFoo
lets GCC compile just fine. VS2015 still gives the warning. - Removing
constexpr
and splitting the declaration from the definition fixes the warning, but why should I have to do that?
OUT_OF_BOUNDS isn't local, and it isn't temporary, right? Does it not have an address when it is defined and declared inside of the class definition?
See the warning live: https://godbolt.org/z/fv397b9rr
CodePudding user response:
What happens when you use the constexpr
in your function is that a temporary local instance is created. You could try to leave out constexpr
and static
in the declaration of your static member OUT_OF_BOUNDS
so you have a const
object / instance you can get a reference of.
EDIT:
If you must have a static member, declare it const static int
and put in the definition const int Foo::OUT_OF_BOUNDS = -1;
in an appropriate place.
CodePudding user response:
The problem is that in C 11, we have to add a corresponding definition for a static constexpr declaration of a class' data member. This is explained in more detail below:
C 11
class Foo
{
public:
static constexpr const int OUT_OF_BOUNDS_VALUE = -9999; //THIS IS A DECLARATION IN C 11 and C 14
//other members here
};
In the above code snippet(which is for C 11,C 14), we have a declaration of the static data member OUT_OF_BOUNDS_VALUE
inside the class. And so, in exactly one translation unit we have to provide a corresponding definition. Otherwise you'll get a linker error which can be seen here.
That is, in exactly one translation unit we should write:
constexpr const int Foo::OUT_OF_BOUNDS;//note no initializer
C 17
class Foo
{
public:
static constexpr const int OUT_OF_BOUNDS_VALUE = -9999; //THIS IS A DEFINITION IN C 17
//other members here
};
In the above code snippet(which is for C 17) we have a definition of the static data member OUT_OF_BOUNDS_VALUE
inside the class. So since C 17, we don't have to provide the definition of OUT_OF_BOUNDS_VALUE
anywhere else since we already have a definition for it inside the class.
The warning that you're getting with MSVC seems to be a bug.
CodePudding user response:
test[i]
is an int
, you're binding it to a reference to const int
in the return statement. No?