Алмазное наследование с шаблонным базовым классом: Base ‹Derived›

У меня проблема с алмазом при наследовании от шаблонного базового класса, который принимает класс Derived в качестве аргумента шаблона.

Обычно эта проблема решается с помощью виртуального наследования следующим образом:

class Base0
{
protected:
    int var = 0;
};

class Base1 : public virtual Base0
{
};

class Base2 : public virtual Base0
{

};

class Derived :
    public Base1,
    public Base2
{
public:
    void f()
    {
        var = 1; // OK single var
    }
};

Однако у меня есть такой сценарий:

template<typename DERIVED_CLASS>
class TemplatedBase0
{
protected:
    int var = 0;
};

class Base1 : public virtual TemplatedBase0<Base1>
{
};

class Base2 : public virtual TemplatedBase0<Base2>
{

};

class Derived :
    public Base1,
    public Base2
{
public:
    void f()
    {
        var = 1; // ERROR: var is ambigous
    }
};

Я понимаю, что в приведенном выше случае шаблонный базовый класс не совпадает, т.е. задействованы 2 полностью нереализованных базовых класса, и похоже, что виртуальное наследование не работает.

Итак, мой вопрос: есть ли способ заставить эту работу работать? какой дизайн / подход мне здесь выбрать?

Мне нужен базовый класс в качестве шаблона, который принимает тип производного класса. но как сделать возможным наследование алмаза?


person metablaster    schedule 13.10.2019    source источник


Ответы (2)


Если вы хотите, чтобы в Derived был только один int var;, вам нужно переместить его в базовый класс, не являющийся шаблоном:

class GenericTemplatedBase0
{
  protected:
    int var = 0;
};

template<typename DERIVED_CLASS>
class TemplatedBase0 : virtual public GenericTemplatedBase0
{
    // ...
};

class Base1 : public TemplatedBase0<Base1>
{
};

class Base2 : public TemplatedBase0<Base2>
{
};

class Derived : public Base1, public Base2
{
  public:
    void f()
    {
        var = 1;
    }
};
person HolyBlackCat    schedule 13.10.2019
comment
Да, это именно то, что мне нужно и чего я хочу, спасибо друг! - person metablaster; 14.10.2019

В вашем коде нет ромба. В вашем Derived есть два разных var. В зависимости от того, что вы хотите написать:

Base1::var = 1;
Base2::var = 1;

но как сделать возможным наследование алмаза?

Непонятно, зачем вам бриллиант. Если ваша цель - иметь только один var в Derived, вам нужен другой дизайн.

person 463035818_is_not_a_number    schedule 13.10.2019