0

The question is easy to explain in code.

I have coded several template classes that they derive from a unique template class:

template<typename T,unsigned N> 
struct DElem : 
    public BElem<T> 
{};

My problem arises when I have to code a container of these anterior derived types from a container of the base class:

template<typename T, unsigned N>
struct DContainer<DElem<T,N>> : 
    public BContainer<BElem<T>>
{};

In my concrete case, Container could be std::tuple or std::array.

My first approximation is:

template<typename T, T B, std::size_t N>
struct DContainer : 
    public std::array<BElem<T>,N> 
{

   // This container is to hold **DElem<T,B>**
   // 
   // This class has to do a cast for every
   // 
   // **DElem<T,B>** (that is what the DContainer holds) 
   //
   // to **BElem\<T\>**
   // 
   // *If this task is easy I don't found the way*

};

Someone has an idea to do these tasks more easy or some other design more appropiate?

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
Earendil
  • 23
  • 5
  • 1
    From what I can see, the problem is you're deriving from `BContainer>` rather than `BContainer>`. – WhozCraig Apr 21 '22 at 21:32
  • Yes, the problem is that **BContainer>** cannot depend of the other template argument (in this case, an unsigned). The base class **BContainer>** is a unique class for all **N unsigned int** **DContainer>**. idem as the **BElem** is a unique base class for all **N unsigned int** cases **DElem**. – Earendil Apr 21 '22 at 21:41
  • 1
    I have no idea what you just said. Your topmost container is supposed to be holding elements of type `DElem` That much is clear. Naturally, if your container derives from some base container that does the actual "holding", it too should know what that is: again, `DElem` . If that isn't the case, then something in your design is questionable. – WhozCraig Apr 21 '22 at 21:54
  • I think that something not is good. But I don't know that could be. **DElem** are digits of a radix B to represent numbers. I derive **template DElem** from a wrapper class for an unsigned integer type: **template BElem { T m_d; };**. The numbers that I want represent are, for example, **std::array,N>**, but **I need** a base class for all these numbers, that can't be **std::array,N>**. – Earendil Apr 21 '22 at 22:15

1 Answers1

0

You are out of luck. A container of DElem<T, N> is not substitutable for a container of BElem<T>. If it could, the following nonsense would be allowed.

DContainer<T, 10> d10Container;
BContainer<T> & bContainer = d10Container;
DElem<T, 20> d20;
bContainer.push_back(d20); // pushed a d20 into a container of d10

What you can have is a view of BElem<T>

template<typename T>
class BView {
    class iterator {
        using value_type = BElem<T>;
        using reference = BElem<T> &;
        using pointer = BElem<T> *;
        using difference_type = std::ptrdiff_t;
        using iterator_category = std::forward_iterator_tag; // or whatever
        reference operator*();
        pointer operator->();
        // etc...
    };

    virtual iterator begin() = 0;
    virtual iterator end() = 0;

    // no insert / push_back / whatever
};

You probably want to hide (or delete) the assignment operator of BElem<T>, because polymorphic assignment is also fairly nonsensical.

Now you have a shared base class for all your DContainer<T, N>s which doesn't permit nonsense.

Alternatively, if you don't need runtime polymorphism, you can just define a concept for BContainer. Using the pre-concept Container requirements as a base:

template<container C, typename T>
concept BContainer = std::derived_from<typename C::value_type, BElem<T>>;
Caleth
  • 52,200
  • 2
  • 44
  • 75