I wish to make the existence of member
within dat
dependent on B
(or some other concept).
template <bool B>
struct dat {
void member_func() requires (B) {} //ok
std::byte member requires (B); //err
};
I know this is possible to do with specialisation but as far as I am aware that would get very ugly if multiple different member requirements were nessacary.
Is this behaviour possible without specialisation?
CodePudding user response:
There's a couple approaches to this (see Conditional Members).
One is you use the condition to change the type of member
:
struct E { };
[[no_unique_address]] std::conditional_t<B, std::byte, E> member;
This isn't really a conditional member variable, member
is always present. But it's sometimes the type you care about and other times it's an empty type that takes no space. That could be good enough - if you never actually have to access the thing, and no code depends on the presence of this member.
If that doesn't work, then you do have to resort to a different sort of specialization. But you don't have to specialize all of dat
, just a base class that conditionally provides this member:
template <bool B>
struct maybe_member {
std::byte member;
};
template <>
struct maybe_member<false> { };
template <bool B>
struct dat : maybe_member<B> {
void member_func() requires (B) {} //ok
};
Here, dat<true>
has a member named member
but dat<false>
has no data members. Which is important for things like iterator_category
(as I mention).
Neither are great solutions, but both definitely beat having to specialize the entire class just to condition on member variable. Both scale if there is a need to have multiple different, independently conditional variables.