如何将可变参数CRTP基类设置为派生类的朋友

问题描述 投票:0回答:1

问题的主要部分是将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";
}

Runable example code

c++ variadic-templates friend crtp policy-based-design
1个回答
0
投票

我能想到的解决方案是使用特征类,该特征类由您创建并定义的类[[之前 CRTP基础和策略所继承,因此它们将是完整的类。特性类可能包含指向您需要到达的成员的指针或引用,具有这些特征的类所共享的类型声明等,请参见在标准组件中如何完成

© www.soinside.com 2019 - 2024. All rights reserved.