struct Config
{
int version = 1;
};
template<Config& config /* , ... */>
struct Peripheral
{
const Config config_ = config;
static_assert(config_.version > 1, "Config version must be greater than 1");
/* ... */
};
Config myConfig;
int main()
{
myConfig.version = 5;
Peripheral<myConfig> peripheral;
}
I want to check at compile-time if the configurations given to my template are correct.
So I am trying to cast my reference to a constant instance in order to try to use it in my static_assert, but I get the error: 'invalid use of non-static data member ...'
Is there a way to check the values of a non-type parameter at compile-time in this case? Or do you have other suggestions to achieve this goal?
CodePudding user response:
If you want the value of myConfig
to be used at compile-time, then you should mark it constexpr
and give it its value directly in the initializer. Whether it is a static or automatic storage duration variable is then secondary:
constexpr Config myConfig = { .version = 5 };
// alternatively before C 20 for example
// constexpr Config myConfig = { 5 };
/*...*/
Peripheral<myConfig> peripheral;
Then the template should take the parameter by-value, not by-reference, and you should use that template parameter directly in the static_assert
:
template<Config config /* , ... */>
struct Peripheral
{
static_assert(config.version > 1, "Config version must be greater than 1");
/* ... */
};
Depending on what else is in Config
or if you are not using C 20 or later, the type might not be allowed as by-value template parameter. In that case you can keep using a reference parameter (although I am not sure that this is good design) but you would need to make it const Config&
instead to match the const
implied by constexpr
. In this case it does matter that myConfig
has static storage duration (specifically it may be declared at namespace scope, as a static
data member or since C 17 as static
local variable).
If you want to keep on using a local config_
copy to assert on, that copy should also be marked constexpr
(const
is not enough to make a variable usable at compile-time) and hence must also be marked static
(because non-static
data members cannot be declared constexpr
).
The value of the template parameter and static_assert
cannot be (potentially) determined at run-time, so myConfig.version = 5;
will never work.