Using std::pair<T1,T2> with ABC interfaces

A

Andrey Vul

Given

// Interface Q
// Implementations R, S
// Caller P

#include <iostream>
#include <utility>

class Q { public: virtual void s() = 0; };
class R : public Q { public: virtual void s()
{ std::cout<<"x"<<std::endl; } };
class S : public Q { public : virtual void s()
{ std::cout<<"y"<<std::endl; } };
class P { public: Q& q; P(Q& q) : q(q) {}; void R() { q.s();} };

int main() {
R r;
S s;
std::pair<int, Q> t = std::make_pair(5, r); // error
std::pair<int, Q*> u = std::make_pair(5, &r); // works
P u(t.second), w(*(u.second));
u.R(); v.R();

}

, an std::pair<,> containing an interface causes an error because
std::pair requires concrete types. Is there a workaround (apart from
using pointer-to-interface everywhere, which feels like using the C
sledgehammer) so that ABCs can be used in std::pair<,> ? My code uses
interface/ABC methods quite a lot and I'm organizing the data
structures as part of cleaning up the code. Are other STL containers
also unable to work directly with ABCs?
 
S

SG

[...] Is there a workaround (apart from
using pointer-to-interface everywhere, which feels like using the C
sledgehammer) so that ABCs can be used in std::pair<,> ?

Not really. You need a pointer *somewhere*. There are a couple of
options and the right one depends on what you're actually trying to
do:

- raw pointer
- shared_ptr (Boost or TR1 or C++0x)
- unique_ptr (C++0x)
- some kind of "value semantics"-emulating wrapper
(similar to a unique_ptr but calls Base::clone on copy)

template<class Base>
class polyvalue
{
public:
/// takes ownership, will call delete on the pointer
explicit polyvalue(Base* p=0)
: ptr_(p)
{}

/// creates a new copy via the clone member function
polyvalue(polyvalue const& x)
: ptr_(x.ptr_ ? x.ptr_->clone() : 0)
{}

~polyvalue()
{ delete ptr_; }

void swap(polyvalue & that)
{ std::swap(this->ptr_,that.ptr_); }

friend void swap(polyvalue & a, polyvalue & b)
{ a.swap(b); }

polyvalue& operator=(polyvalue tmp)
{ tmp.swap(*this); return *this; }

Base const& operator*() const { return ptr_; }
Base & operator*() { return ptr_; }
Base const* operator->() const { return ptr_; }
Base * operator->() { return ptr_; }
Base const* get() const { return ptr_; }
Base * get() { return ptr_; }
private:
Base* ptr_;
};

(untested)

Cheers!
SG
 
A

Andrey Vul

[...] Is there a workaround (apart from
using pointer-to-interface everywhere, which feels like using the C
sledgehammer) so that ABCs can be used in std::pair<,> ?

Not really. You need a pointer *somewhere*. There are a couple of
options and the right one depends on what you're actually trying to
do:

Calling a virtual function defined in a derived class using a pointer
to a base class whose typeid evaluates to said derived class,
  - raw pointer
  - shared_ptr (Boost or TR1 or C++0x)
  - unique_ptr (C++0x)
  - some kind of "value semantics"-emulating wrapper
    (similar to a unique_ptr but calls Base::clone on copy)

I'll look at the boost docs to see which template wrapper works best.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,150
Members
46,696
Latest member
BarbraOLog

Latest Threads

Top