Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type erasure for methods with differing in return types

I was wondering if some form of type erasure exists for dealing with methods that have the same name and arguments but return different values like in my example below (begin and end). I'm not planning on actually using this anywhere I'm just interested in knowing if it's possible, and, if so, how it would be done.

The only form of type erasure I know about is having a pointer to a pure virtual concept class which points to a model<T> which forwards calls to the underlying T. However, this requires that all the T's contain methods with the exact same signature, while in my example the return types differ. As far as I can tell something akin to virtual template functions would be needed to do what I'm asking, but I may be missing something.

class Iterable
{
    //how would this be defined?
}

int main(int argc, char *argv[])
{
    vector<int> v = {1, 2, 3, 4, 5};
    set<string> s = {"foo", "bar", "baz"};

    Iterable iterable;

    if(argc == 2) iterable = v;
    else iterable = s;


    for(auto val : it)
    { 
        cout << val << ' ';
    }
}
like image 693
Adam Avatar asked Dec 21 '22 13:12

Adam


1 Answers

Type erasure can and has been implemented in C++ in different contexts. The most common approach, which is used in boost::any, std::function< signature >, std::thread and others is based on a non-polymorphic class that is the type erased object, which contains a pointer to an interface type. Internally, during construction, assignment or whenever the user type is erased, an implementation of the interface is instantiated and stored.

As a motivating simplified example, consider that we wanted to create a printable type that can be used to print any type that implements operator<< to std::cout using type erasure. For that we need the type printable, the internal interface printable_impl_base, and the actual implementations:

// regular polymorphic hierarchy:
struct printable_impl_base {
   virtual ~printable_impl_base() {}
   virtual void print() const = 0;
};
template <typename T>
struct printable_impl : printable_impl_base {
   T copy_to_print;
   printable_impl( T const & o ) : copy_to_print( o ) {}
   virtual void print() const {
      std::cout << copy_to_print << std::endl;
   }
};

// type erasure is performed in printable:
class printable {
   std::shared_ptr<printablable_impl_base> p;
public:
   template <typename T>
   printable( T obj ) : p( new printable_impl<T>(obj) ) {}
   void print() const {
      p->print();
   }
};

Note that the pattern is very similar to a regular polymorphic hierarchy, with the difference that an interface object is added that is a value type (borrowing the term value type from C#), that holds the actual polymorphic objects inside.

Looking at it this way, it seems kind of simplistic and useless, but that is the fuel that drives boost::any (the internal interface is only a typeid), std::function< void () > (the internal interface is that it implements void operator()), or shared_ptr<> (the interface is the deleter method, that relinquishes the resource).

There is one specific different type of type erasure when the only thing that needs to be done with the type that implements type erasure is to destroy it: use a temporary and bind it to a constant reference... But this is very specific, if you want you can read about it here: http://drdobbs.com/cpp/184403758

In the specific case that you are talking about in the question it is a bit more complex, because you don't want to erase a single type, but rather a couple of them. The Iterable interface must erase the type of the container that it internally holds, and in doing so it has to provide it's own iterators that have to perform type erasure on the iterators from the container. Still, the idea is basically the same, just more work to do to implement.

like image 174
David Rodríguez - dribeas Avatar answered Dec 28 '22 06:12

David Rodríguez - dribeas