Date: Mon, 24 Jul 2023 23:31:18 +0100
You'll occasionally see the following inside C++ files:
MyClass &GetMyClass(void)
{
static MyClass obj;
return obj;
}
#define g_obj (GetMyClass())
Since C++11, this code uses a "once_flag" behind the scenes to make
sure that it's threadsafe.
The only problem here with using the preprocessor to define 'g_obj' is
that we can't control the scope -- we can't put 'g_obj' inside a
namespace. We also need to make sure that nobody names anything
'g_obj' anywhere.
But, what if we could remove the preprocessor from the equation by
providing a syntax for functions to take "void void" instead of
"void". So we would define the function as follows:
MyClass &g_obj(void void)
{
static MyClass obj;
return obj;
}
So now in our code wherever we write "g_obj", it's as if we had
written "g_obj()".
Then we could do stuff like:
std::optional<T> g_opt;
T &g_obj(void void)
{
if ( false == g_opt.has_value() ) std::abort();
return g_opt.value();
}
We could also apply a constraint that the function must return an
L-value reference.
If you don't like the "void void" then we could have another syntax like:
T &g_obj =
{
if ( false == g_opt.has_value() ) std::abort();
return g_opt.value();
};
Using this alternative syntax, we could even put it inside a function body:
int main(void)
{
T &g_obj =
{
if ( false == g_opt.has_value() ) std::abort();
return g_opt.value();
};
g_obj.SomeMethod();
}
P.S. Totally unrelated to this, in a couple of days I'll post a paper
on NRVO working with over a dozen compilers
MyClass &GetMyClass(void)
{
static MyClass obj;
return obj;
}
#define g_obj (GetMyClass())
Since C++11, this code uses a "once_flag" behind the scenes to make
sure that it's threadsafe.
The only problem here with using the preprocessor to define 'g_obj' is
that we can't control the scope -- we can't put 'g_obj' inside a
namespace. We also need to make sure that nobody names anything
'g_obj' anywhere.
But, what if we could remove the preprocessor from the equation by
providing a syntax for functions to take "void void" instead of
"void". So we would define the function as follows:
MyClass &g_obj(void void)
{
static MyClass obj;
return obj;
}
So now in our code wherever we write "g_obj", it's as if we had
written "g_obj()".
Then we could do stuff like:
std::optional<T> g_opt;
T &g_obj(void void)
{
if ( false == g_opt.has_value() ) std::abort();
return g_opt.value();
}
We could also apply a constraint that the function must return an
L-value reference.
If you don't like the "void void" then we could have another syntax like:
T &g_obj =
{
if ( false == g_opt.has_value() ) std::abort();
return g_opt.value();
};
Using this alternative syntax, we could even put it inside a function body:
int main(void)
{
T &g_obj =
{
if ( false == g_opt.has_value() ) std::abort();
return g_opt.value();
};
g_obj.SomeMethod();
}
P.S. Totally unrelated to this, in a couple of days I'll post a paper
on NRVO working with over a dozen compilers
Received on 2023-07-24 22:24:49