Reputation: 789
So, I've seen questions here on how to set global constant variables at runtime by prompting the user for input then using cin
. However, I need to be able to set a constant global variable based on one of the arguments passed to main (ie from argc
/argv
). All of the solutions I found involved having a constructor function defined above the const variable's declaration, but this won't work if I can only access argc
and argv
from main.
Is this at all possible? How could I implement this?
Edit: Here's the question that talks about cin
, for reference: Are there any tricks to use std::cin to initialize a const variable?
Upvotes: 2
Views: 2522
Reputation: 2570
It is not possible to initialize global constants at main
. By the time your program reaches it, all globals must have already been initialized.
However, it is possible to write a class that contains a value and only allows you to set it once. The check will have to be done at runtime, however.
Something like this (std::optional
requires C++17, but you don't have to use it):
#include <optional>
template <typename T>
class LateConstant
{
public:
LateConstant() = default;
LateConstant(const LateConstant&) = delete;
LateConstant& operator=(const LateConstant&) = delete;
LateConstant& operator=(const T& x)
{
if (!v.has_value())
{
v = std::make_optional<T>(x);
}
else
{
std::terminate();
}
return *this;
}
bool has_value() const
{
return v.has_value();
}
const T& value() const
{
return v.value();
}
private:
std::optional<T> v;
};
With this, if you try to assign a value more than once, your program intentionally crashes. It's not a constant, but it may still be useful.
Now, to be honest, you'd better avoid globals anyway. I haven't used them in years, after I've been bitten several times. If you decide not to use globals, you can use constant locals instead or collect the data you need in a class and pass that around.
Another possibility is to use something like
int whatever(int i = 0)
{
static const int stored = i;
return stored;
}
If you try to set it more than once, it will just ignore the value, which could be a bad idea.
Upvotes: 2
Reputation: 118445
Objects in global scope gets constructed before main
() gets invoked, so it's logically impossible to use main
's argc
and argv
to construct them. This is a fairly fundamental chicken-and-egg problem, and there is no portable way around it.
It might be possible to cheat and use function static scope to simulate it, something like:
class MySingleton {
public:
MySingle(int argc, char **argv);
// ...
}
const MySingleton &global_singleton(int argc=0, char **argv=nullptr)
{
static MySingleton instance{argc, argv};
return instance;
}
int main(int argc, char **argv)
{
global_singleton(argc, argv);
}
This might work as long as nothing else in global scope calls global_singleton
in its constructor. main()
does it ASAP, passing in the real argc
and argv
, and everyone else just calls it with the useless parameters defaulted.
Upvotes: 3