I run into the following problem and idk if it can be solved in an elegant way:
wifi
and sntp
in main. I can't do it in global space because they are dependent on a task scheduler which is started only when main is called.So I'm landing in cyclic dependency land once again. My initial thought to fight through this was to just forward declare the static variable but it turns out this doesn't work in the way that I thought, as declaring it "extern" conflicts with the later definition.
Here's the code:
#include <cstdio>
#include <functional>
struct wifi_config {
std::function<void()> callback;
};
struct wifi {
wifi(const wifi_config& cfg) {}
};
struct sntp {
sntp() = default;
auto start() -> void { printf("SNTP start!\n"); }
};
int main() {
extern sntp mysntp;
static wifi mywifi(wifi_config{
.callback = [&]() -> void {
mysntp.start();
}
});
static sntp mysntp;
}
And here's the error:
<source>:28:17: error: 'sntp mysntp' conflicts with a previous declaration
28 | static sntp mysntp;
|
How do I get around this?
The most painless way is to put them both as members of the same struct. The order the members are declared in the struct is the order that they are constructed in:
int main() {
struct statics {
wifi mywifi{
wifi_config{
.callback = [this]() -> void {
mysntp.start();
}
}
};
sntp mysntp;
};
static auto [ mywifi, mysntp ] = statics();
}
This has very slightly different semantics if one of the constructors were to throw, but this shouldn't be a problem in main()
.
Also, a static in main
is kind of useless because they will be destroyed when main exits, very similarly to if they had been automatic variables. If you were to switch to automatic variables, you could just remove the static
in static auto [ ...
.
To answer your question literally, it is possible to "forward declare" static variables (get a reference to them before they have been initialized):
int main() {
// fake "forward declaration"
constexpr auto get_mysntp = [](sntp init()){
static sntp mysntp(init());
return std::integral_constant<sntp*, &mysntp>{};
};
constexpr sntp& mysntp = *decltype(get_mysntp(nullptr))::value;
static wifi mywifi(wifi_config{
.callback = [&]() -> void {
mysntp.start();
}
});
// fake "definition" (actually construct the static variable)
get_mysntp([]{ return sntp{}; });
}
Which may be useful if your example is more complicated. The struct
of statics is probably enough.