I'd like to construct some state machines using constexpr in C++, which requires the states and their transitions to be constexpr as well. If the state machine has a cyclical portion (eg. state 1 has a transition to state 2, and state 2 has a transition to state 1), then cyclical constexpr is required. However, code such as the following doesn't compile (MSVC 2017) as constexpr must be initialized at declaration:
class a
{
public:
constexpr a(a const & v) : v(v) {}
a const & v;
};
constexpr extern a x;
constexpr a y = a(x);
constexpr a x = a(y);
Is there a workaround, or a plan to address this in a future revision of the C++ standard?
Edit: Based on erenon's comment, I tried this:
class a
{
public:
constexpr a(a const & v) : v(v) {}
a const & v;
};
constexpr a x_getter();
constexpr a y_getter() {
return a(x_getter());
}
constexpr a x_getter() {
return a(y_getter());
}
constexpr a test = x_getter();
but it fails with an interesting warning message: Warning C4591 'constexpr' call-depth limit of 512 exceeded
and expression did not evaluate to a constant
errors at the last line.
You can hide x
and y
inside a class (or struct). Even if you did not want to have recursive references, this would be beneficial for reasons of information encapsulation:
#include <iostream>
class a
{
public:
// use `a const *` to avoid overriding default copy-constructor
constexpr a(a const *v_) : v(*v_) {}
a const & v;
};
struct state_machine
{
a const x,y;
constexpr state_machine() : x(&y), y(&x) {}
private:
// can't copy or move a state_machine (this implicitly deletes operator=):
state_machine(state_machine&&) = delete;
};
constexpr state_machine sm;
int main(int argc, char **argv) {
std::cout << "&x: " << &sm.x << ", &x.v: " << &sm.x.v << '\n';
std::cout << "&y: " << &sm.y << ", &y.v: " << &sm.y.v << '\n';
// state_machine sm2{sm}; // forbidden
}
Above code was tested with g++ versions 5.4.1 and 6.2.0 using -std=c++11
and -std=c++14
. I don't have MSVC to check that.