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).