I would like to conditionally add some data members to a base class, conditioned on the presence of a derived data member.
In the below example, Extra
is the base class template, which will be switched on the template parameter Enable
.
The consteval
function enable
is used to detect the presence of the derived data member, the return value of which will be used to select which version of Enable
we want.
Foo
is the base class to which we want to add the extra functionality, and Bar
is the derived type which declares the requisite member which we are using the enable the extra functionality.
#include <iostream>
template<bool Enable>
struct Extra
{
static constexpr bool is_enabled = false;
};
template<>
struct Extra<true>
{
static constexpr bool is_enabled = true;
int extra { 42 };
};
template<typename T>
consteval bool enable()
{
if constexpr (requires { T::enable_extra; })
return true;
else
return false;
}
template<typename T>
struct Foo : Extra<enable<T>()>
{
using Base = Extra<enable<T>()>;
using Base::is_enabled;
void eval()
{
if constexpr (is_enabled)
{
if (static_cast<T*>(this)->enable_extra)
std::cout << "extra=" << Base::extra << 'n';
}
}
};
struct Bar : Foo<Bar>
{
const bool enable_extra = true;
};
int main()
{
Bar b;
b.eval();
return 0;
}
Suffice to say it doesn’t work, and enable<T>()
evaluates to false at the point at which it is called.
My current hypothesis is that this is due to Bar
being incomplete at the point at which Foo
is instantiated, and therefore T::enable_extra
doesn’t yet exist, so the if constexpr
evaluates to false.
Is what I’m trying to do here even possible? Am I able to add base class functionality based on the presense of a member in the derived class?