If my class is a literal class then is it redundant to declare an object of my class as constexpr?

There is a major difference: only dbg2 can be used where a constant expression is required. As an example, consider the upcoming C++20 feature that allows arbitrary non-type template parameters:

template <Debug> void f() { }

With the above definition, f<dgb2>() will compile, while f<dgb>() will not.

f<dgb>();
<source>:7:29: note:   template argument deduction/substitution failed:

<source>:13:12: error: the value of 'dbg' is not usable in a constant expression
   13 |   foo<dbg>();  // ERROR
      |            ^

<source>:10:9: note: 'dbg' was not declared 'constexpr'
   10 |   Debug dbg(true, false, false); // is dbg constexpr object?

live example on godbolt.org


This is also significant in C++11. You will be able to say:

template <bool> void g() { }
g<dgb2.a>();

But not:

g<dgb.a>();

live example on godbolt.org


Simple demonstration of how the two variables are different:

struct Debug {
  constexpr Debug(bool a, bool b, bool c) : a(a), b(b), c(c) {}
  bool a, b, c;
  constexpr bool get() const { return a; }
};

int main() {
  Debug dbg(true, false, false); // dbg is not a constant
  constexpr Debug dbg2(0, 0, 0); // constexpr makes this a constant expression

  // *** Begin demo ***
  dbg.a = false;
  //dbg2.a = false; //< error: assignment of member 'Debug::a' in read-only object
  // *** End demo ***
}

The value of dbg can be changed, while the value of dbg2 cannot.

To get a Debug object that is a constant expression, you need both the constexpr qualifier in the constructor (to allow a Debug object to be flagged as a constant expression) and the constexpr qualifier in the variable declaration (to flag that object as a constant expression).

Tags:

C++

Oop

Constexpr