Why don't static member variables play well with the ternary operator?
Here's the deal. I have a static class which contains several static functions used for getting input. The class contains a private static member variable for indicating whether the user entered any information. Each input method checks to see whether the user entered any information, and sets the status variable accordingly. I think this would be a good time to use the ternary operator. Unfortunately, I can't, because the compiler doesn't like that.
I replicated the problem, then simplified my code as much as was possible to make it easy to understand. This is not my original code.
Here's my header file:
#include <iostream>
using namespace std;
class Test {
public:
void go ();
private:
static const int GOOD = 0;
static const int BAD = 1;
};
Here's my implementation with the ternary operator:
#include "test.h"
void Test::go () {
开发者_如何转开发 int num = 3;
int localStatus;
localStatus = (num > 2) ? GOOD : BAD;
}
Here's main function:
#include <iostream>
#include "test.h"
using namespace std;
int main () {
Test test = Test();
test.go();
return 0;
}
When I try to compile this, I get this error message:
test.o: In function `Test::go()':
test.cpp:(.text+0x17): undefined reference to `Test::GOOD'
test.cpp:(.text+0x1f): undefined reference to `Test::BAD'
collect2: ld returned 1 exit status
However, if I replace this:
localStatus = (num > 2) ? GOOD : BAD;
with this:
if (num > 2) {
localStatus = GOOD;
} else {
localStatus = BAD;
}
The code compiles and runs as expected. What obscure C++ rule or GCC corner case is responsible for this lunacy? (I'm using GCC 4.4.1 on Ubuntu 9.10.)
This is according to the C++ Standard. The ternary operator does constitute a single lvalue that will refer to either GOOD
or BAD
at runtime. The lvalue to rvalue conversion is not applied immediately to either the lvalue GOOD
or BAD
, and therefor you require a definition of GOOD
and BAD
.
See the core language issue report http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#712 .
As a workaround, you can apply explicit casts to int
(which reads their values, thereby doing an lvalue to rvalue conversion) or use an operator that reads the value, like +
:
localStatus = (num > 2) ? +GOOD : +BAD;
class Test {
static const int GOOD = 0;
static const int BAD = 1;
};
These are only declarations; they are not definitions. You need to provide definitions of the static member variables, outside of the definition of the class, in one of your .cpp files:
const int Test::GOOD;
const int Test::BAD;
Alternatively, for integer constants, it is often more convenient to use an enum
:
class Test {
enum {
GOOD = 0,
BAD = 1
};
};
Your code looks fine to me. And ideone
agrees: see this link. But that's with gcc-4.3.4. However, my gcc-4.4.0 doesn't accept it. So whatever the reason, it's not obvious.
Edited to add: The following variant compiles under gcc-4.4.0:
int localStatus = 42 ? GOOD : BAD;
Reminder: the following code doesn't compile:
int localStatus = (num == 42) ? GOOD : BAD;
So somebody has screwed up somewhere.
精彩评论