Suppose I have a template class, which depending on a template parameter, may or may not have a member int x
.
This can be realized by inheriting from a base template class, which for some specialization has a member int x
.
Example code:
#include <iostream>
template <bool present>
struct base;
template <>
struct base<true> { int x; };
template <bool present>
struct base { };
template <bool activate>
struct A : public base<activate> {
void print() const;
};
template <bool activate>
void A<activate>::print() const
{
if constexpr (activate) {
std::cout << "x = " << this->x << std::endl;
} else {
std::cout << "nothing" << std::endl;
}
}
int main()
{
A<true> a;
a.print();
A<false> b;
b.print();
return 0;
}
In the code above A<true>
contains a member int x
, inherited from base<true>
, whereas A<false>
does not contain it.
Now, since x
is a dependent name, in order to access it, I need to use this->x
or base<true>::x
. This can be somewhat burdersome to use it every time, so the common solution is to employ a using
directive like
using base<true>::x;
inside the definition of A
. But, of course, this makes sense only when activate=true
.
Is it possible, perhaps with a macro, to add using base<true>::x
in the definition of A
, only when a condition (here activate=true
) is satisfied?
CodePudding user response:
It's a common issue to have optionally present members. If you're okay with multiple inheritance and some hacking, you can do this via a static
empty variable in another base class:
struct Nothing {};
struct StaticNothing {
static Nothing x;
};
template <bool activate>
struct A : public base<activate>, StaticNothing {
using std::conditional_t<activate, base<true>, StaticNothing>::x;
void print() const;
};
Note that std::conditional_t<>
decides which base x
comes from. The benefit of this method is, you can always assume that there's an x
member (either static or non-static), so you can take the address of it, etc.
CodePudding user response:
base on the comment of @Jarod42, but use anonymous class (optional) and inline variable to make sure it compiles without extra definitions. (regarding to OP's this comment)
template <bool present>
struct base { constexpr static struct{} x = {}; };
template <>
struct base<true> { int x = 0; };
template <bool activate>
struct A : public base<activate> {
using base<activate>::x;
void print() const;
};
CodePudding user response:
another placeholder option is use a function, with the benefit that one can delete
it to prevent unwanted access.
template <bool present>
struct base { constexpr void x()=delete; };
template <>
struct base<true> { int x = 0; };
template <bool activate>
struct A : public base<activate> {
using base<activate>::x;
void print() const{
auto&& p = x; // fail for A<false>::print
}
};