Основная часть проблемы заключается в использовании CRTP с дизайном на основе политик и вариативным шаблоном. Из политики не удается получить доступ к защищенным или закрытым членам основного/производного класса. Из-за использования вариативного шаблона я не могу объявлять политики просто друзьями.
Вопрос в том, как я могу установить все классы политики в качестве друзей производного класса.
Учитывая это решение CRTP, что поддерживает несколько уровней наследования и решает проблемы с алмазами без виртуального наследования.
// Derived - We would like to obtain access to this type of instance
// BaseDerived - Helper type to avoid the diamond problem without virtual inheritance
template<typename Derived, template<typename> class BaseDerived>
class Crtp {
protected:
[[nodiscard]] constexpr Derived & underlying() noexcept
{
return static_cast<Derived &>(*this);
}
[[nodiscard]] constexpr Derived const & underlying() const noexcept
{
return static_cast<Derived const &>(*this);
}
};
// Helper struct to achive multiple inheritance
struct NoDerivedClassTag;
template<template<typename> class Derived, typename Substitute, template<typename> class Base>
using DerivedCrtpBase = Base<std::conditional_t<std::is_same_v<Substitute, NoDerivedClassTag>, Derived<NoDerivedClassTag>, Substitute>>;
template<template<typename> class Interface, typename Object>
using is_crtp_interface_of = std::enable_if_t<
std::is_same_v<Interface<NoDerivedClassTag>, Object> || std::is_base_of_v<Interface<typename Object::exact_type>, Object>>;
Использование этого решения CRTP в дизайне на основе политик с вариативным шаблоном, подобным этому
template<template<typename> class... Functionality>
class FinalDerived
: public Functionality<FinalDerived<Functionality...>>...
{
public:
constexpr int get() const
{
return protected_variable_;
}
// Remove to check the problem
//protected:
int protected_variable_ {-1};
};
Цель состоит в том, чтобы использовать защищенную переменную из политики, подобной этой.
template<typename Derived>
struct Increment
: Crtp<Derived, Increment>
{
void increment(int an_value)
{
this->underlying().protected_variable_ += an_value;
}
};
template<typename Derived>
struct Decrement
: Crtp<Derived, Decrement>
{
void decrement(int an_value)
{
this->underlying().protected_variable_ -= an_value;
}
};
Пример использования
constexpr int number {7};
int main(void){
FinalDerived<Increment, Decrement> derived;
std::cout << "start: " << derived.get() << "\n";
derived.increment(number);
std::cout << "incremented: " << derived.get() << "\n";
derived.decrement(number);
std::cout << "decremented: " << derived.get() << "\n";
}