Home > Back-end >  access to optionally present members of base template class
access to optionally present members of base template class

Time:01-05

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;
};

Demo

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
    }
};
  • Related