Imagine I have the following class:
class Extra final
{
public:
void Method1() const {std::cout << "Method 1" << std::endl;}
void Method2() const {std::cout << "Method 2" << std::endl;}
};
I created, for some class T
, a class template that can enable/disable methods using Extra
at compile time according to different scenarios (listed in an enum):
enum class Scenario
{
None, // No extra.
One, // Only Method1 allowed.
Two, // Only Method2 allowed.
Both // Both Method1 and Method2 allowed.
};
The class template looks as follow:
template<typename T, Scenario R>
class ExtraAdder : public T
{
};
template<typename T>
class ExtraAdder<T, Scenario::One> : public T
{
public:
void Method1Extra() const {m_extra.Method1();}
private:
Extra m_extra;
};
template<typename T>
class ExtraAdder<T, Scenario::Two> : public T
{
public:
void Method2Extra() const {m_extra.Method2();}
private:
Extra m_extra;
};
template<typename T>
class ExtraAdder<T, Scenario::Both> : public T
{
public:
void Method1Extra() const {m_extra.Method1();}
void Method2Extra() const {m_extra.Method2();}
private:
Extra m_extra;
};
It can be used as follow:
class Base
{
public:
virtual ~Base() = default;
void BaseMethod() const {std::cout << "Base method" << std::endl;}
// Some other stuff...
};
int main(int argc, char **argv)
{
std::cout << "Scenario: None" << std::endl;
ExtraAdder<Base, Scenario::None> none;
none.BaseMethod();
//none.Method1Extra(); // Does not compile.
//none.Method2Extra(); // Does not compile.
std::cout << std::endl << "Scenario: One" << std::endl;
ExtraAdder<Base, Scenario::One> one;
one.BaseMethod();
one.Method1Extra();
//one.Method2Extra(); // Does not compile.
std::cout << std::endl << "Scenario: Two" << std::endl;
ExtraAdder<Base, Scenario::Two> two;
two.BaseMethod();
//two.Method1Extra(); // Does not compile.
two.Method2Extra();
std::cout << std::endl << "Scenario: Both" << std::endl;
ExtraAdder<Base, Scenario::Both> both;
both.BaseMethod();
both.Method1Extra();
both.Method2Extra();
return 0;
}
The point is that by changing the template parameter Scenario
, I can only have access to some method(s) of the wrapped m_extra
member, which is exactly what I want. However, as you can see, the different specializations are very verbose (and have some duplication).
Question: Is there a way to produce the exact same template specializations, but in a less verbose way, with limited or no duplication?
The closest I have found to solve this is this question (using std::enable_if
), but I have not been able to adapt it to my case.
I am using g++ with the C++17 standard.