-1

When I do this

Txtbin a;

switch(err){
    case a.ERR_EMPTY_IMAGE:
        std::cerr << "Error: Image is empty\n" << std::endl;
        break;
}

I get this error

txtbin.cpp: In function ‘int main(int, char**)’: txtbin.cpp:97:11: error: the value of ‘a’ is not usable in a constant expression case a.ERR_EMPTY_IMAGE: ^

The constant ERR_EMPTY_IMAGE is defined as follows in the class:

public:
    const int ERR_EMPTY_IMAGE   = 2;
Christophe
  • 68,716
  • 7
  • 72
  • 138
clarkk
  • 27,151
  • 72
  • 200
  • 340

1 Answers1

0

In short

In your class Txtbin, define the const as static:

public:
    static const int ERR_EMPTY_IMAGE   = 2; 

then

switch(err){
    case Txtbin::ERR_EMPTY_IMAGE:
        std::cerr << "Error: Image is empty\n" << std::endl;
        break;
}

In very long, with all the explanations

Why static ?

In fact the way you initialize your constant makes clear that it is not specific to any object: You do not intend to have a different value for ERR_EMPTY_IMAGE in two objects of your class.

The right way to tell this to the compiler is to make this const static. This makes the constant independent of any object of the class. You can then refer to it only with Txtbin::ERR_EMPTY_IMAGE wherever you want.

Once it is static, you could also keep using a.ERR_EMPTY_IMAGE in the switch, since the compiler will find out that it doesn't need the non-const object a to determine the value.

Note also that the size of the objects would also be smaller since static values do not need to be duplicated in every instance.

Why is const not sufficient here ?

You can very well have a public const that is different for every object of the class:

class Test2 {
public:
    const  int ERR_EMPTY_IMAGE;    
    Test2(int x) : ERR_EMPTY_IMAGE{x} {}
};
 
Test2 c(5), d(6); 
cout << "Test2 c ->"<< c.ERR_EMPTY_IMAGE<<" d->"<< d.ERR_EMPTY_IMAGE<<endl; 

The const does only tell that the value of the member does not change once the object is constructed. And this is why your compiler complained in the first instance: the const is not sufficient for the compiler to define it at compile time. Proof:

class Test1 {
public:
    const  int ERR_EMPTY_IMAGE   = 2;  
    Test1() = default;                  // default constructor 
    Test1(int x) : ERR_EMPTY_IMAGE{x} {}
};

Test1 b;  
Test1 b_ouch(9); 
cout << "Sizeof b: "<< sizeof(b) <<endl;  
cout << "Test1 b ->"<< b.ERR_EMPTY_IMAGE<<" b_ouch->"<< b_ouch.ERR_EMPTY_IMAGE<<endl; 

Here an online demo of what is said above

Would constexpr be even better ?

constexpr is the way to say to the compiler that you expect the expression to be constant at compile time. So the kind of expression you could use in a case.

Now for all the reasons explained above, constexpr requires anyway your member variable to be static:

public:
    constexpr static int ERR_EMPTY_IMAGE   = 2;   

The main advantage of constexpr in your case would be to highlight any misunderstandings sooner. Because you could very well have your member defined like this

public:
    const static int ERR_EMPTY_IMAGE; 

and initialize its value outside the class. This makes it very tricky. Semantically, for C++ this is still a static constant (i.e. its value will never change). And in the compilation unit in which the constant is initialized, it'll be used as a compile time constant thanks to constant propagation. But in other compilation units, its value is not known at compile time (it might be known only at link time).

With constexpr instead of const the compiler would immediately complain by telling you that the initialization is missing in the declaration. So it could be an advantage to use it, at least if you do not have to use some older compiler.

Community
  • 1
  • 1
Christophe
  • 68,716
  • 7
  • 72
  • 138