Reputation: 2652
I have a class that I regularly use for an enum wrapper, however this requires a cpp file. Can anyone show me how to use constexpr
The header file is as follows:
// Extend-able in the future
class CDUVariable {
public:
enum Value {
baud, firmware, type, serial
};
static const CDUVariable Baud, Firmware, Type, Serial;
/// Comparison operator (used for strict weak ordering).
bool operator<(const CDUVariable& rhs) const {
return mValue < rhs.mValue;
}
/// Integral operator cast for switch statements (cast to named enum).
operator const Value() const {
return mValue;
}
/// Serialized version of the enum.
std::string getStringVal() const {
return mStringVal;
}
static const std::set<CDUVariable>& getValues() {
static std::set<CDUVariable> gValues;
if (gValues.empty()) {
gValues.insert(Baud);
gValues.insert(Firmware);
gValues.insert(Type);
gValues.insert(Serial);
}
return gValues;
}
static CDUVariable valueOf(const std::string& rStringVal) {
for (const auto& next : getValues()) {
if (next.getStringVal() == rStringVal) {
return next;
}
}
throw std::invalid_argument(
"Illegal Argument: " + rStringVal);
}
private:
CDUVariable(const Value& rValue, const std::string& rStringVal)
: mValue(rValue)
, mStringVal(rStringVal)
{}
Value mValue;
std::string mStringVal;
};
and the cpp file is:
const CDUVariable CDUVariable::Baud(baud, "0");
const CDUVariable CDUVariable::Firmware(firmware, "1");
const CDUVariable CDUVariable::Type(type, "2");
const CDUVariable CDUVariable::Serial(serial, "3");
I would like to know if it is possible to use the new constexpr syntax to initialize everything in the header file. I am having trouble with the syntax.
I tried prefixing modifying the header as follows:
// Extend-able in the future
class CDUVariable {
public:
constexpr enum Value {
baud, firmware, type, serial
};
constexpr static CDUVariable Baud(baud, "0") Firmware(firmware, "1"), Type(type, "2"), Serial(serial, "3");
But this ended up giving me a bunch of errors. I would like to know how to migrate to the new constexpr syntax and the plus side of this would be that I could ship a header only library containing these enum type classes.
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(107): error C2061: syntax error: identifier 'baud'
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(107): error C3646: 'Firmware': unknown override specifier
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(107): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(107): error C2059: syntax error: '('
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(147): error C2143: syntax error: missing ')' before ';'
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(147): error C2098: unexpected token after data member 'mValue'
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(147): error C2059: syntax error: ')'
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(111): error C2065: 'mValue': undeclared identifier
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(111): error C2039: 'mValue': is not a member of 'CDUVariable'
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(102): note: see declaration of 'CDUVariable'
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(116): error C2065: 'mValue': undeclared identifier
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(126): error C3867: 'CDUVariable::Baud': non-standard syntax; use '&' to create a pointer to member
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(127): error C2065: 'Firmware': undeclared identifier
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(128): error C2065: 'Type': undeclared identifier
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(129): error C2065: 'Serial': undeclared identifier
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(146): error C2614: 'CDUVariable': illegal member initialization: 'mValue' is not a base or member
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(165): error C2350: 'CDUVariable::Baud' is not a static member
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(165): note: see declaration of 'CDUVariable::Baud'
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(165): error C2248: 'CDUVariable::CDUVariable': cannot access private member declared in class 'CDUVariable'
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(143): note: see declaration of 'CDUVariable::CDUVariable'
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(102): note: see declaration of 'CDUVariable'
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(166): error C2039: 'Firmware': is not a member of 'CDUVariable'
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(102): note: see declaration of 'CDUVariable'
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(166): error C2065: 'firmware': undeclared identifier
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(167): error C2039: 'Type': is not a member of 'CDUVariable'
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(102): note: see declaration of 'CDUVariable'
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(167): error C2065: 'type': undeclared identifier
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(168): error C2039: 'Serial': is not a member of 'CDUVariable'
2>c:\users\johnc\main\app739\include\vcdu\vcduconstants.h(102): note: see declaration of 'CDUVariable'
2>c:\users\johnc\main\app739\src\vcdu\vcduconstants.cpp(168): error C2065: 'serial': undeclared identifier
2>Generating Code...
Upvotes: 1
Views: 1713
Reputation: 50550
I have a class that I regularly use for an enum wrapper, however this requires a cpp file. Can anyone show me how to use constexpr
To reduce your example to a minimal one, consider the following class:
struct Example {
enum Value { A, B };
static constexpr Example Foo{Value::A, "bar" };
constexpr Example( Value v, std::string s): v{v}, s{s} {}
private:
Value v;
std::string s;
};
This is more or less a reduced version of your last attempt.
Almost all the pieces required to be able to construct a constexpr
version of Example
are in place, but for the fact that:
static constexpr
data members must be initialized, but Example
is an incomplete type at the point of declaration of Foo
.
All the data members must be (let me say) constexpr
constructible and std::string
hasn't a constexpr
constructor you can use.
Therefore your attempt will fail, no doubts about that.
Moreover, note that you cannot odr-use constexpr
data members unless you are using C++17 or you define them separately in a .cpp
file, exactly as you did until now. That's because those members are not implicitly defined in C++11/14.
It means that you cannot even use them with std::set::insert
for it accepts only references. At least, you cannot use them unless you put a definition in a .cpp
file, of course.
So, back to the question:
Can anyone show me how to use constexpr
No, we cannot and it doesn't worth it. It seems to me that you want odr-usable data members, so go on with static
ones and put definitions in a dedicated file.
Upvotes: 2
Reputation: 48958
By definition, an enum values are constant, after all, you can't add values at runtime. That's why one reason you are not allowed to put constexpr
before an enum declaration, it would make no sense, as it wouldn't change anything about the enum
:
constexpr enum Value { baud, firmware, type, serial };
^^^^^^^^^
illegal
As a side note, you cannot construct a constexpr
CDUVariable
right now because its constructor is not constexpr
. If you try to mark it appropriately, it will fail, because mStringVal
doesn't have a constexpr
constructor and every variable has to be initialized.
If you are only going to store single characters, use a char
, which as a primitive, is able to be constructed at compile time.
Upvotes: 2
Reputation: 217293
You may get rid of those static variables with:
static const std::set<CDUVariable>& getValues() {
static const std::set<CDUVariable> gValues = {
{ baud, "0"}, // or Baud(),
{ firmware, "1"},
{ type, "2"},
{ serial, "3"}
};
return gValues;
}
and
static const CDUVariable& Baud() { static const CDUVariable var{ baud, "0"}; return var; }
or
static CDUVariable Baud() { return { baud, "0"}; }
Upvotes: 1