Covariant return type with primitive types

206 Views Asked by At

I have the following:

template<typename T>
class AbsContainer {
public:
    virtual T operator[](ptrdiff_t) = 0;
};

template<typename T>
class SpecialContainer : public AbsContainer<T>, Box<pair<ptrdiff,T>> {
    class Proxy;
public:
    Proxy operator[](ptrdiff_t i) {
        return Proxy(i, this);
    };
};

template <typename T>
class SpecialContainer<T>::Proxy  {
    ptrdiff_t _i;
    Box* _p;
public:
    Proxy(ptrdiff_t i, Box* p) : _i(i), _p(p);
    Proxy& operator=(const T& elm) {
        _p->::insert(pair<ptrdiff,T>(_i,elm));  //defined in Box
    }
};

main:

SpecialContainer<int> x;
x[2] = 3;

This doesn't compile, because in class SpecialContainer, the operator[] with the one in AbsContainer.

Ideally in concept, Proxy operator[] should be an override. So I tried resolving this by achieving covariant return type by making Proxy inherit from T. However it doesn't work since T can be a primitive type, and inheriting from a primitive type has no sense.

Error because of operator conflict :

error: conflicting return type specified for ‘specialContainer<T>::Proxy B<T>::operator[](std::ptrdiff_t) [with T = int; std::ptrdiff_t = long unsigned int]

Error because trying to inherit from parametric type T (int in this case):

error: base type ‘int’ fails to be a struct or class type

Is there any way in which can this be resolved ?

1

There are 1 best solutions below

17
n. m. could be an AI On

You can implement something very similar to covariant types even without any compiler support for actual covariant types. Here's how to do it.

#include <cstddef>
#include <map>
#include <string>
#include <iostream>

template<typename T>
class AbsContainer {
  public:
    T operator[](ptrdiff_t i) { return operator_Abs(i); }
    virtual T operator_Abs(ptrdiff_t) = 0;
};

template<typename T>
class SpecialContainer : public AbsContainer<T>, std::map<ptrdiff_t, T>  {
  public:
    class Proxy;
    Proxy operator[](ptrdiff_t i) { return operator_Spec(i); }
    T operator_Abs(ptrdiff_t i) override {
        return operator_Spec(i).get();
    }
    virtual Proxy operator_Spec(ptrdiff_t i) {
        return Proxy(i, this);
    }
};

template <typename T>
class SpecialContainer<T>::Proxy  {
    ptrdiff_t _i;
    std::map<ptrdiff_t, T>* _p;
public:
    Proxy(ptrdiff_t i, std::map<ptrdiff_t, T>* p) : _i(i), _p(p) {};
    Proxy& operator=(const T& elm) {
        _p->insert(std::pair<ptrdiff_t,T>(_i,elm));
        return *this;
    }
    T get() { return (*_p)[_i]; }
};

int main()
{
       SpecialContainer<std::string> spec;
       AbsContainer<std::string>& abs = spec;
       auto k = spec[42];
       k = "Hello World";
       std::cout << abs[42] << "\n";
}