Reputation: 7832
I'd like to do the following (which won't compile):
class Foo {
int value;
Foo(const int arg)
: value{arg}
{}
public:
static const Foo a{0};
static const Foo b{1};
static const Foo c{2};
Foo func(const Foo& foo) {...}
};
so that the the instances of Foo
are strongly controlled (like in an enum
) and so that I can write code like auto foo = Foo::a;
and auto foo = Foo::a.func(Foo::b);
Unfortunately, the code won't compile under C++11 because the static instances have incomplete type.
Is there an idiom for this?
Upvotes: 2
Views: 102
Reputation: 39513
You can do it quite easily but you need to put the definitions of your constants outside the class:
class Foo {
int value;
// In C++17, you could make this constexpr.
Foo(const int arg)
: value{arg}
{}
public:
// in C++20, you could make these constinit.
static const Foo a;
static const Foo b;
static const Foo c;
};
// In C++11 these need to go in the source file to avoid linker errors.
// In C++17 you could make them inline and put them in the header.
// In C++20 you could make them constinit.
const Foo Foo::a = 0;
const Foo Foo::b = 1;
const Foo Foo::c = 2;
I wouldn't call this an elegant solution though. Particularly in C++11, these constants can't be inlined by the compiler because they need to go into the source file. This can have a significant impact on performance. So if you're going to do it, I would recommend using at least C++17, if not C++20.
Generally, C++ enums are meant to be integer constants and there is no support for getting the ordinal or name of an enum
like there is in Java. An alternative approach is to use an enum class
with no values (which defaults to values 0, 1, 2, ...) and then use them as indices inside of lookup tables.
Using a switch
for properties can also do the trick:
enum class Axis : unsigned { X, Y, Z };
// in C++17, you could make this constexpr.
inline const char *nameOf(Axis axis)
{
switch (axis) {
case Axis::X: return "X";
case Axis::Y: return "Y";
case Axis::Z: return "Z";
}
}
Upvotes: 2