I've tried implementing a list container,
and decided to move some general functions
like sum() to base class, so that I can
reuse them later in other containers.
All the base support class needs are three
methods empty(), head() and tail.
I can't make those pure virtual because support
class will never be instantiated. But it still
has to use those methods to implement its own
methods like sum().
I tried something like this:
#include <iostream>
using namespace std;
template<typename T>
class StatsSupport {
public:
T sum(void) const {
if (empty()) {
return T(0);
} else {
return head() + tail()->sum;
}
}
// other methods
};
template<typename T>
class List : public StatsSupport<T> {
public:
// constructors etc.
bool empty(void) const {return head_ != NULL;}
const T& head(void) const {return *head_;}
const List<T>& tail(void) const {return *tail_;}
// other methods
private:
T* head_;
List<T> *tail_;
};
But trying to use sum() gets me compilation error
prog.cpp:8:13: error: there are no arguments to 'empty' that depend on a template parameter, so a declaration of 'empty' must be available [-fpermissive]
if (empty()) {
^
for each of empty(), head() and tail().
Any advice?
The problem is that StatsSupport cannot find the empty, head etc. functions because these neither exist in its nor in the global scope.
StatsSupport does not know about the functions that exist in the derived class.
Basically there are two ways to solve this:
Runtime polymorphism, where you add a virtual destructor to StatsSupport and add declarations for empty, head etc. which are pure virtual.
Compile time polymorphism via using CRTP as mentioned in the comments.
I will focus on the latter.
So basically StatsSupport needs to get a way to access functions of the derived class.
This can be done by adding the type of the derived class as template parameter, which is called CRTP:
template<class Derived, typename T>
class StatsSupport {
public:
T sum(void) const {
if (derived()->empty()) {
return T(0);
} else {
return derived()->head() + derived()->tail()->sum;
}
}
// other methods
private:
Derived *derived()
{
return static_cast<Derived*>(this);
}
const Derived *derived() const
{
return static_cast<const Derived*>(this);
}
};
template<typename T>
class List : public StatsSupport<List<T>, T> { // with some changes could be simplified to StatsSupport<List<T>> but this it ouf of scope of this question
I am using a function for derived instead of a member to keep the class const correct.
Of course another alternative would be a different design relying on algorithms. There you move sum and all the other functions of StatsSupport into global namesapce and would then access them like sum(my_container_instance).
A more STL like way would be to use iterators. Then you could use std::accumulate to do the summing.
That's a serious design issue: Your StatSupport defines some general functions, but relies on specifics of its child classes.
So when StatSupport gets compiled, it doesn't even know that there is some head() and tail(). That's why you get the error message
Now imagine that one day you want to define other containers that shall inherit from StatSupport, for example your own Vector or Map, or DataBase. These data structures will not have a head and a tail.
Basically there are two main orientations you may take:
define in your StatSupport some virtual functions for iterating through the data structure.
or better, use in your data structures some iterators (like they exist for standard containers) and define some template functions (sum, average, etc...) that use iterators to browse through your container.
In the latter case, you wouldn't need inheritance to benefit from generic functions.
I might miss the point of the question but will give my 5 cents to it anyway :)
The reasoning behind the solution I show below is, that often people new to OOP (in C++) think that they must use inheritance to get things done.
But especially in C++, this is but one way and often not the best way to achieve composition.
While in the majority of cases, the overhead cost of virtual functions does not really matter, the code below shows a way to yield container expansions without using inheritance and without using virtual functions. The weak point of the approach is that the "container function contract" is only implicitly visible.
template <class _X>
class ContainerTypeA < _X >
{
public:
typedef _X value_type;
typedef ContainerTypeA<_X> container_type;
const _X & Head() const
{
// return head of this containers content.
}
container_type Tail() const
{
// return the tail (all elements after the first element in a new instance.
}
bool IsEmpty() const
{
return true; // return whether or not this container is empty.
}
};
template <class _X>
class ContainerTypeB < _X >
{
public:
typedef _X value_type;
typedef ContainerTypeB<_X> container_type;
const _X & Head() const
{
// return head of this containers content.
}
container_type Tail() const
{
// return the tail (all elements after the first element) in a new instance.
}
bool IsEmpty() const
{
return true; // return whether or not this container is empty.
}
};
// Note: In stead of the class with static member functions, this could
// as well be a namespace with template-functions inside.
template < class _ContainerT >
class ContainerStats<_ContainerT>
{
static _ContainerT::value_type Sum(const _ContainerT & container)
{
// Implement sum - possibly in the recursive way you did in your question.
}
// more expansion functions...
};
Related
I have C++11 project that uses inheritance. Here is small fragment:
class ICountable{
public:
virtual ~ICountable(){}
unsigned getCount() const{
return _getCount();
}
bool isEmpty() const{
return _getCount() == 0;
}
private:
virtual unsigned _getCount() const = 0;
};
Suppose we have some LinkList that inherits from ICountable and implements _getCount(). Then you can make function like this:
void doSomething(ICountable &countable){
if (countable.isEmpty())
doSomethingElse();
}
...
LinkList ll;
doSomething(ll);
This is all very good, but there must be another way to do all this:
template <typename T>
void doSomething(T countable){
if (countable.isEmpty())
doSomethingElse();
}
...
LinkList ll;
doSomething(ll); // we do not even need to add <>
Template way is faster and probably easier to implement. std::vector and std::deque are like this as well.
However, how I can avoid code duplication - function isEmpty() must be pasted in all "list things".
I can imagine preprocessor #include or...
I can imagine decorator-like class that may implements all those sugar methods and to proxy the others:
template <typename T>
class List{
T list;
public:
unsigned getCount() const{
return list.getCount();
}
bool isEmpty() const{
return list.getCount() == 0;
}
...
}
What is better inheritance or templates, if there will be no runtime polymorphism?
Is there better way to avoid code duplication?
There is a C++ feature that has not been formally added to the standard (but has been in the works for quite some time) called Concepts that would essentially let you declare your doSomething(T countable) to have the requirement that T implement a certain interface (ie, that it has an isEmpty() function). Until then, you can't avoid polymorphism if what you want is to avoid code duplication by sharing a set of common functions (re: interface) between different classes. That's one of the main reasons to use polymorphism in the first place.
With that said, you are looking for the Curiously Recurring Template Pattern like Igor Tandetnik mentioned in the comments. This allows you to share common code between classes without the runtime penalty of virtual functions (runtime polymorphism). Using CRTP lets the compiler do that stuff for you.
Using a simple base class:
template <typename T>
struct ICountable {
bool isEmpty() const { return static_cast<T*>(this)->_getCount() == 0; }
};
And then your derived list:
class LinkedList : public ICountable<LinkedList> {
int _getCount() const { return size; }
};
Any class that derives from ICountable in this way will now have an isEmpty() method that uses the implementation-specific _getCount() method without the use of virtual functions.
With templates, you just imply the interface. You write a function template and require that the type you pass in meets your criteria. In this case, just:
template <typename T>
void doSomething(T const& countable) {
if (countable.empty()) {
doSomethingElse();
}
}
All the C++ standard containers have an empty() method, and you could do worse than copy the standard interfaces for containers that you write yourself. This function already works for vector and list and string and ..., all without any dynamic dispatch overhead or without the OOP requirements of having to inherit from some interface.
Generic programming works if the types have the interface you need - they don't need to inherit from all the correct named interfaces to get them.
Here's what I'm trying to accomplish:
I'm trying to created a linked list of various types. In order to accomplish this, I figured polymorphism would be a great way to go about.
I have two classes, AttributeBase and Attribute. AttributeBase is used by AttributeSet, which just stores the start and end points of the linked list of Attribute<T>'s (as AttributeBase*'s) and does modification on the list. AttributeBase is a base class of Attribute<T> that is only in the design for the sake of making generic pointers. Attribute<T>, of course, is the specific type of AttributeBase where the actual value is stored. The main data of each Attribute<T> is an inherited string (the attribute's name, or 'key' if you will) and a value of type T.
So, thus far I have (simplified):
class AttributeBase
{
public:
AttributeBase() = delete;
AttributeBase* GetNext() { return next; };
AttributeBase* GetPrev() { return prev; };
std::string GetName() { return name; };
//Sometimes I need to get/set the value stored in a derived class
//But, how would I define the function here since the return
//type is of type T as defined in Attribute?
virtual ???? GetValue = 0;
virtual void SetValue(????) = 0;
friend class AttributeSet;
private:
AttributeBase* next = nullptr;
AttributeBase* prev = nullptr;
std::string name;
};
template <class T>
class Attribute : public AttributeBase
{
public:
Attribute( std::string _name, T _value ){ name = _name; value = _value };
T GetValue(){ return value; };
void Setvalue(T){ value = T; };
private:
T value;
};
class AttributeSet
{
public:
template <class T>
void Add(std::string,T); //Add an Attribute<T>(std::string,T) to the list
void Delete(std::string);
bool Contains(std::string _name); //Scan the list to determine if an
//attribute with name of _name exists
template <class T>
T Get(std::string); //Scan the list for 'name' and return
//AttributeBase*->GetValue()
private:
AttributeBase* start = nullptr;
AttributeBase* end = nullptr;
}
Since I tried to keep AttributeBase generic and non-templated (to avoid strongly-typed start and end pointers in AttributeSet), this brings up a problem. How do I specify an as-of-yet unspecified return type for the virtual function BaseAttribute::GetValue(). I first tried using auto, got a compile error.
Being as no instances of AttributeBase are ever actually created (and the default constructor deleted) I figured it would be possible to leave out GetValue and define it in the derived class. However, if I try *AttributeBase->GetValue() it errors out since GetValue() isn't defined in AttributeBase, only the subclasses. You would think the compiler would know that the pointer has to point to a derived class (the only derived type) since AttributeBase cannot be directly constructed.
So, in order to use GetValue() I have to know the type of the previous value ahead of time to be able to cast the AttributeBase* to an Attribute*. This would be trivial if AttributeBase itself were templated and contained a value T type. I could then just access AttributeBase*->type to determine the type of pointer I need to cast. However, like I said, templating AttributeBase destroys the intended use of the object.
More than likely, I'm going about this in a completely wrong way (yet again). But at this point I am stuck for ideas. Any help would be appreciated!
So a truly general solution doesn't exist. You just can't get any arbitrary type from a base class because all your overrides of your base class virtual function have to have the same return type.
That leaves you two options.
First, you can decide in advance that you're going to have your list hold any object that derives from some common base type. This will severely limit what you can put into your list, but at least you have full freedom with those objects once they're there.
Second, depending on what you want to actually do with the objects once they're in your list, you can look at the new Boost.TypeErasure library. If all you need to do with list is, say, output them all, or some either small amount of operations, this can help you get there.
Since the signatures of GetValue and SetValue depend on a type, they need to be templates. But they can be template members without requiring a class template.
class AttributeBase
{
public:
template <typename T> T GetValue() const;
template <typename T> void SetValue(T);
//...
};
template <typename T>
T AttributeBase::GetValue() const
{
return dynamic_cast<Attribute<T>&>(*this).GetValue();
}
template <typename T>
void AttributeBase::SetValue(T val)
{
dynamic_cast<Attribute<T>&>(*this).SetValue(val);
}
template <typename T>
T AttributeSet::Get(std::string const& name) const
{
// (assuming a private helper method Find().)
const AttributeBase* attr = Find(name);
if ( !attr )
throw std::invalid_argument("attribute not in set");
return attr->GetValue<T>();
}
One gotcha, though: these functions will all throw an exception if you happen to use the wrong type. And SetValue might automatically deduce its template argument, and might do so incorrectly. For example, if a is a AttributeBase& reference which is really an Attribute<long int>, then a.SetValue(1) is the same as a.SetValue<int>(1), which will throw. The correct expression would be a.SetValue<long int>(1) (or a.SetValue(1L), but I'd prefer the explicit template argument).
What are the ways in C++ to handle a class that has ownership of an instance of another class, where that instance could potentially be of a number of classes all of which inherit from a common class?
Example:
class Item { //the common ancestor, which is never used directly
public:
int size;
}
class ItemWidget: public Item { //possible class 1
public:
int height;
int width;
}
class ItemText: public Item { //possible class 2
std::string text;
}
Let's say there is also a class Container, each of which contains a single Item, and the only time anyone is ever interested in an Item is when they are getting it out of the Container. Let's also say Items are only created at the same time the Container is created, for the purpose of putting them in the Container.
What are the different ways to structure this? We could make a pointer in Container for the contained Item, and then pass arguments to the constructor of Container for what sort of Item to call new on, and this will stick the Items all in the heap. Is there a way to store the Item in the stack with the Container, and would this have any advantages?
Does it make a difference if the Container and Items are immutable, and we know everything about them at the moment of creation, and will never change them?
A correct solution looks like:
class Container {
public:
/* ctor, accessors */
private:
std::unique_ptr<Item> item;
};
If you have an old compiler, you can use std::auto_ptr instead.
The smart pointer ensures strict ownership of the item by the container. (You could as well make it a plain pointer and roll up your own destructor/assignment op/copy ctor/move ctor/ move assignment op/ etc, but unique_ptr has it all already done, so...)
Why do you need to use a pointer here, not just a plain composition?
Because if you compose, then you must know the exact class which is going to be composed. You can't introduce polymorphism. Also the size of all Container objects must be the same, and the size of Item's derived classes may vary.
And if you desperately need to compose?
Then you need as many variants of Container as there are the items stored, since every such Container will be of different size, so it's a different class. Your best shot is:
struct IContainer {
virtual Item& getItem() = 0;
};
template<typename ItemType>
struct Container : IContainer {
virtual Item& getItem() {
return m_item;
}
private:
ItemType m_item;
};
OK, crazy idea. Don't use this:
class AutoContainer
{
char buf[CRAZY_VALUE];
Base * p;
public:
template <typename T> AutoContainer(const T & x)
: p(::new (buf) T(x))
{
static_assert(std::is_base_of<Base, T>::value, "Invalid use of AutoContainer");
static_assert(sizeof(T) <= CRAZY_VAL, "Not enough memory for derived class.");
#ifdef __GNUC__
static_assert(__has_virtual_destructor(Base), "Base must have virtual destructor!");
#endif
}
~AutoContainer() { p->~Base(); }
Base & get() { return *p; }
const Base & get() const { return *p; }
};
The container requires no dynamic allocation itself, you must only ensure that CRAZY_VALUE is big enough to hold any derived class.
the example code below compiles and shows how to do something similar to what you want to do. this is what in java would be called interfaces. see that you need at least some similarity in the classes (a common function name in this case). The virtual keyword means that all subclasses need to implement this function and whenever that function is called the function of the real class is actually called.
whether the classes are const or not doesn't harm here. but in general you should be as const correct as possible. because the compiler can generate better code if it knows what will not be changed.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class outputter {
public:
virtual void print() = 0;
};
class foo : public outputter {
public:
virtual void print() { std::cout << "foo\n"; }
};
class bar : public outputter {
public:
virtual void print() { std::cout << "bar\n"; }
};
int main(){
std::vector<outputter *> vec;
foo *f = new foo;
vec.push_back(f);
bar *b = new bar ;
vec.push_back(b);
for ( std::vector<outputter *>::iterator i =
vec.begin(); i != vec.end(); ++i )
{
(*i)->print();
}
return 0;
}
Output:
foo
bar
Hold a pointer (preferably a smart one) in the container class, and call a pure virtual clone() member function on the Item class that is implemented by the derived classes when you need to copy. You can do this in a completely generic way, thus:
class Item {
// ...
private:
virtual Item* clone() const = 0;
friend Container; // Or make clone() public.
};
template <class I>
class ItemCloneMixin : public Item {
private:
I* clone() const { return new I(static_cast<const I&>(*this); }
};
class ItemWidget : public ItemCloneMixin<ItemWidget> { /* ... */ };
class ItemText : public ItemCloneMixin<ItemText> { /* ... */ };
Regarding stack storage, you can use an overloaded new that calls alloca(), but do so at your peril. It will only work if the compiler inlines your special new operator, which you can't force it to do (except with non-portable compiler pragmas). My advice is that it just isn't worth the aggravation; runtime polymorphism belongs on the heap.
I have a particular class that stores a piece of data, which implements an interface:
template<typename T>
class MyContainer : public Container<T> {
class Something : public IInterface {
public:
// implement *, ->, and ++ here but how?
private:
T x;
};
// implement begin and end here, but how?
private:
Something* data; // data holds the array of Somethings so that references to them can be returned from begin() and end() to items in this array so the interface will work, but this makes the problem described below
};
And I have an array of Somethings.
I have the need for Something to implement an interface class (IInterface in the example) which:
Contains pure virtual member functions which return something such that *retval returns a reference to the x member, retval-> returns the address of x, and ++retval makes retval refer to the next Something in the array.
The things that the pure virtual members return can be inherited from and returned by the implementation of the members
container[i] (where container is the array holding the Something objects) always returns something such that *retval always returns a reference to the same T for the same i.
Right now, the interface looks like this:
template<typename T>
class Container {
class IInterface {
public:
virtual T& operator*() = 0;
virtual T* operator->() = 0;
virtual IInterface& operator++(); // this is the problem
};
// returning a reference right now to support covariance, so subclasses can
// derive from Container and then have a member class derive from IInterface
// and override these to return their derived class, but this has a problem
virtual IInterface& begin() = 0;
virtual IInterface& end() = 0;
};
My current solution (have the virtual methods return an IInterface& and return a Something& in the implementation) has no problem with the requirements, except for the ++retval requirement. Because the Something is directly tied to the object it holds and can't point to a T with a pointer, there's no way that I can find to get ++ to make the variable refer to the next Something in the array.
If it helps to know, this is an iterator type system. I would have made it with the STL style iterators (where you just have an array of T) that are passed around by value and hold pointers to the values they represent, but that would break the interface because only references and pointers are covariant, and the objects already have to exist somewhere else already (in my code they're in the array) so you don't return a reference to a local object.
The purpose of this setup is so that one can write functions that take a Container& and iterate the container without knowing what type of container it is:
void iterate(Container<int>& somecontainer) {
Container<int>::IIterator i = somecontainer.begin(); // right now this would return a reference, but it doesn't/can't work that way
while (i != somecontainer.end()) {
doSomething(*i);
++i; // this is the problem
}
}
It's kind of difficult for me to describe, don't hesitate to let me know if you need more information.
What you are trying to do is called type erasure. Basically you want to provide a value type (which is the same across the whole inheritance hierarchy) that wraps the particular iterator type and offers a uniform dynamic interface.
Type erasure is usually implemented with a non-virtual class (the type erased) that stores a pointer to a virtual base class that implements the erasure, from which you derive different types that wrap each particular iterator. The static class would offer templated constructor/assignment operators that would dynamically instantiate an object of the derived type and store the pointer internally. Then you only need to implement the set of operations as dispatch to the internal object.
For the simplest form of type erasure possible, you can take a look at the implementation of boost::any (documentation is here)
Sketch:
namespace detail {
template<typename T>
struct any_iterator_base {
virtual T* operator->() = 0; // Correct implementation of operator-> is tough!
virtual T& operator*() = 0;
virtual any_iterator_base& operator++() = 0;
};
template <typename T, typename Iterator>
class any_iterator_impl : any_iterator_base {
Iterator it;
public:
any_iterator_impl( Iterator it ) : it(it) {}
virtual T& operator*() {
return *it;
}
any_iterator_impl& operator++() {
++it;
return *this;
}
};
}
template <typename T>
class any_iterator {
detail::any_iterator_base<T>* it;
public:
template <typename Iterator>
any_iterator( Iterator it ) : it( new detail::any_iterator_impl<T,Iterator>(it) ) {}
~any_iterator() {
delete it;
}
// implement other constructors, including copy construction
// implement assignment!!! (Rule of the Three)
T& operator*() {
return *it; // virtual dispatch
}
};
The actual implementation becomes really messy. You need to provide different versions of the iterator for the different iterator types in the standard, and the detail of the implementation of the operators might not be trivial either. In particular operator-> is applied iteratively until a raw pointer is obtained, and you want to make sure that your type erased behavior does not break that invariant or document how you break it (i.e. limitations on the type T that your adaptor can wrap)
For extended reading:
- On the Tension Between Object-Oriented and Generic Programming in C++
- any_iterator: Implementing Erasure for C++ iterators
- adobe any_iterator ,
I would suggest a look at the Visitor pattern.
Other than that, what you want is a value type that will be imbued with polymorphic behavior. There is a much simpler solution than James' using your IInterface.
class IInterface
{
virtual ~IInterface() {}
virtual void next() = 0;
virtual void previous() = 0;
virtual T* pointer() const = 0;
virtual std::unique_ptr<IInterface> clone() const = 0;
};
std::unique_ptr<IInterface> clone(std::unique_ptr<IInterface> const& rhs) {
if (!rhs) { return std::unique_ptr<IInterface>(); }
return rhs->clone();
}
class Iterator
{
friend class Container;
public:
Iterator(): _impl() {}
// Implement deep copy
Iterator(Iterator const& rhs): _impl(clone(rhs._impl)) {}
Iterator& operator=(Iterator rhs) { swap(*this, rhs); return *this; }
friend void swap(Iterator& lhs, Iterator& rhs) {
swap(lhs._impl, rhs._impl);
}
Iterator& operator++() { assert(_impl); _impl->next(); return *this; }
Iterator& operator--() { assert(_impl); _impl->previous(); return *this; }
Iterator operator++(int); // usual
Iterator operator--(int); // usual
T* operator->() const { assert(_impl); return _impl->pointer(); }
T& operator*() const { assert(_impl); return *_impl->pointer(); }
private:
Iterator(std::unique_ptr<IInterface> impl): _impl(impl) {}
std::unique_ptr<IInterface> _impl;
};
And finally, the Container class will propose:
protected:
virtual std::unique_ptr<IInterface> make_begin() = 0;
virtual std::unique_ptr<IInterface> make_end() = 0;
And implement:
public:
Iterator begin() { return Iterator(make_begin()); }
Iteraotr end() { return Iterator(make_end()); }
Note:
You can do away with the std::unique_ptr if you can avoid the ownership issue. If you can restrict the IInterface to be behavioral only (by extracting the state into Iterator), then you can have the Strategy pattern kick-in, and use a pointer a statically allocated object. This way, you avoid dynamic allocation of memory.
Of course, it means your iterators won't be so rich, as it requires IInterface implementations to be stateless, and implementing "filtering" iterators, for example, would become impossible.
Have you thought about using CRTP. I find it a good candidate here. Here is a brief demo. It just explains your ++retval problem (if I understood it correctly). You have to change your IInterface definition from pure virtual to CRTP type interface.
template<class Derived>
struct IInterface
{
Derived& operator ++ ()
{
return ++ *(static_cast<Derived*>(this));
}
};
struct Something : public IInterface<Something>
{
int x;
Something& operator ++ ()
{
++x;
return *this;
}
};
There are some limitations of CRTP, that the template will always follow your IInterface. Which means that if you are passing a Something object to a function like this:
foo(new Something);
Then, foo() should be defined as:
template<typename T>
void foo(IInterface<T> *p)
{
//...
++(*p);
}
However for your problem, it can be a good fit.
Like you said, the problem is that instances of Something are tied to the object it holds. So let's try to untie them.
The key point to remember is that in OOP, public non-const data members are generally frowned upon. In your current implementation, every Something instance is tied to having a data member T x which is publicly accessible. Instead of this, is considered better to make an abstraction of this, i.e. provide accessor methods instead:
class Something : IInterface
{
private:
T x;
public:
T GetX()
{
return x;
}
};
Now the user has know idea what type of thing x is, much less that x exists.
This is a good first step, however, since you wish be able to have x refer to different objects at different times, we're pretty much going to have to make x be a pointer. And as a concession to conventional code, we'll also make GetX() return a const reference, rather than a regular value:
class Something: IInterface
{
private:
T *x;
public:
T const& GetX()
{
return *x;
}
};
It's now trivial to implement the methods in IInterface:
class Something: IInterface
{
private:
T *x;
public:
T const& GetX()
{
return *x;
}
T& operator*()
{
return *x;
}
T* operator->()
{
return x;
}
Something& operator++()
{
++x;
return *this;
}
};
The ++ operator is trivial now - it really just applies the ++ to x.
The user now has no idea that a pointer was used. All they know is that their code works right. That's the most important point in OOP's principle of data abstraction.
Edit
As far as implementing the begin and end methods of Container, that shouldn't be too difficult either, but it will require some changes to Container.
First off, let's add a private constructor to Something which takes a pointer to the starting object. We'll also make MyContainer a friend of Something:
class Something: IInterface
{
friend class MyContainer; // Can't test the code right now - may need to be MyContainer<T> or ::MyContainer<T> or something.
private:
T *x;
Something( T * first )
: x(first)
{
}
public:
T const& GetX()
{
return *x;
}
T& operator*()
{
return *x;
}
T* operator->()
{
return x;
}
Something& operator++()
{
++x;
return *this;
}
};
By making the constructor private, and setting the friend dependancy, we ensure that only MyContainer can make new Something iterators (this protects us iterating over random memory if something erroneous were given by a user).
Next off, we'll change MyContainer a little, so that rather than having an array of Something, we'll just have an array of T:
class MyContainer
{
...
private:
T *data;
};
Before we get to implementing begin and end, let's make that change to Container I talked about:
template<typename T, typename IteratorType>
class Container {
public:
...
// These prototype are the key. Notice the return type is IteratorType (value, not reference)
virtual IteratorType begin() = 0;
virtual IteratorType end() = 0;
};
So rather than relying on covariance (which would be really difficult in this case), we use a little template magic to do what we want.
Of course, since Container now accepts another type parameter, we need a corresponding change to MyContainer; namely we need to provide Something as the type parameter to Container:
template<class T>
class MyContainer : Container<T, Something>
...
And the begin/end methods are now easy:
template<class T>
MyContainer<T>::begin()
{
return Something(data);
}
template<class T>
MyContainer<T>::end()
{
// this part depends on your implementation of MyContainer.
// I'll just assume your have a length field in MyContainer.
return Something(data + length);
}
So this is what I've got for my midnight thinking. Like I mentioned above, I cannot currently test this code, so you might have to tweak it a bit. Hopefully this does what you want.
If the usage is supposed to be similar to stdlib, then the iterator needs to be a value object, because it normally gets copied by value a lot. (Also, otherwise what would the begin and end method return a reference to?)
template <class T>
class Iterator
{
shared_ptr<IIterator> it;
public:
Iterator(shared_ptr<IIterator>);
T& operator*() { it->deref(); }
T* operator->() { return &it->deref(); }
Iterator& operator++() { it->inc(); return *this; }
etc.
};
Consider this simplified example:
#include <list>
typedef std::list<int> IntList;
class KindaIntList {
public:
IntList::const_iterator begin() const { /* do some stuff */ }
IntList::const_iterator end() const { /* do some stuff */ }
// ...etc
};
The KindaIntList class implements some of the methods of the STL list.
Now, I have a function
void f(IntList l) {
// do stuff
}
which only calls methods that are implemented by KindaIntList. I would like to be able to call it with an IntList or with a KindaIntList argument. Is that possible?
I thought about using templates, but the definition of f is quite large and I don't want to put it in a header file (f is a member of a class, and I don't want it to be inlined).
Edit
The function f is actually a virtual member of another class; so I'm not sure how to make it into a template member.
Despite your misgivings about templates, this really is an appropriate spot to use C++ templates. Template functions perfectly capture the notion of "this function works with any arguments, as long as the operations I perform on those arguments are well-defined."
You don't need to worry about inlining in this case. Unless you define f inside of the body of a class, it won't automatically be inlined, even if it's a template. For example, in this code:
class MyClass {
public:
template <typename T> void f(T&);
};
template <typename T> void MyClass::f(T&) {
/* ... implementation ... */
}
Because f isn't defined inside of the MyClass body, it's not considered an inline function.
As for your concern about making the header file too large, I contend that this really isn't something to worry about. If you're worried about making the header too large, you can either put a big comment about halfway down saying something like
/* * * * * Implementation Below This Point * * * * */
Alternatively, you could make a separate .h file for the template implementation, then #include that file at the bottom of the header file. This shields the client from seeing the template implementations unless they actively go looking for it.
Hope this helps!
EDIT: If f is virtual, then you cannot make it a template function (as you've probably figured out). Consequently, if you want to make it work for "things that happen to look like std::list," then you don't have many good options. Normally you'd create a base class for both std::list and your custom list type, but this isn't an option as you can't modify std::list.
Fortunately, there is a way to treat std::list and things that look like it polymorphically using a trick called external polymorphism. The idea is that while you can't make the appropriate classes behave polymorphically, you can add an extra layer of indirection around those objects by introducing a polymorphic class hierarchy that just forwards all its requests to the objects that themselves are not polymorphic.
If you're willing to pull out the Big Template Guns, you can encapsulate this logic inside of a class that works much the same way as the new std::function template type. The idea is as follows. First, we'll create a polymorphic base class that exports all the functions you want to call as pure virtual functions:
class List {
public:
virtual ~List() {}
virtual std::list<int>::const_iterator begin() const = 0;
virtual std::list<int>::const_iterator end() const = 0;
virtual void push_back(int value) = 0;
/* ... etc. ... */
};
Now, we can define a template subclass of List that implements all of the public interface by forwarding all of the calls to an object of the actual type. For example:
template <typename T> class ListImpl: public List {
private:
T& mImpl; // Actual object that does the work
public:
/* Constructor stores a reference to the object that actually does the work. */
ListImpl(T& impl) : mImpl(impl) {
// Handled in initializer list
}
/* These functions all forward the requests to the implementation object. */
virtual std::list<int>::const_iterator begin() const {
return mImpl.begin();
}
virtual std::list<int>::const_iterator end() const {
return mImpl.end();
}
virtual void push_back(int value) {
mImpl.push_back(value);
}
/* ... etc. ... */
};
Now that you have this wrapper, you can implement f so that it takes in a List:
class MyClass {
public:
void f(List* myList) {
myList->push_back(137); // For example
}
};
And you can call this function on an object that looks like a list by first wrapping it in an object of type ListImpl. For exmaple:
MyClass mc;
std::list<int> myList;
MyIntList myIntList;
mc->f(new ListImpl<std::list<int> >(myList));
mc->f(new ListImpl<MyIntList>(myIntList));
Of course, this is bulky and unwieldy. You also have to worry about resource leaks, which aren't very fun. Fortunately, you can solve this by wrapping up all the logic to deal with List and ListImpl in a helper class, like this one here:
class ListWrapper {
public:
template <typename ListType> ListWrapper(ListType& list) {
/* Store a wrapper of the appropriate type. */
mImpl = new ListImpl<ListType>(list);
}
/* Delete the associated implementation object. */
~ListWrapper() {
delete mImpl;
}
/* For each interface function, provide our own wrapper to forward the logic
* to the real implementation object.
*/
std::list<int>::const_iterator begin() const {
return mImpl->begin();
}
std::list<int>::const_iterator end() const {
return mImpl->end();
}
void push_back(int value) {
mImpl->push_back(value);
}
/* ... etc. ... */
/* Copy functions necessary to avoid serious memory issues. */
ListWrapper(const ListWrapper& rhs) {
mImpl = rhs.mImpl->clone();
}
ListWrapper& operator= (const ListWrapper& rhs) {
if (this != &rhs) {
delete mImpl;
mImpl = rhs.mImpl->clone();
}
return *this;
}
private:
List* mImpl; // Pointer to polymorphic wrapper
};
You can now write f to take in a ListWrapper like this:
class MyClass {
public:
virtual void f(ListWrapper list) {
list.push_back(137); // For example
}
};
(This assumes that you've updated List and ListImpl with a virtual clone function that makes a copy of the object, which I've omitted for brevity's sake).
And magically, this code is now legal (and safe!):
MyClass mc;
std::list<int> myList;
MyIntList myIntList;
mc.f(myList);
mc.f(myIntList);
This code works because the template constructor for ListWrapper will automatically infer the type of its argument and implicitly create an object of type ListImpl appropriate for that object. It also encapsulates the memory management for you, so you never see any explicit news or deletes. Moreover, it means that you can pass in any object that you'd like and everything will work automatically - we've essentially made anything that looks like a list polymorphic by using a parallel class hierarchy!
Whew! That was fun! Hope this helps!
You could overload f to either take IntList and KindaIntList like this:
void f(IntList l){...}
void f(KindaIntList l){...}
Or make it take iterators:
void f(IntList::iterator first, IntList::iterator last){...}
That said, templates are really the best choice here, for both cases:
template<class ListT>
void f(ListT l){...}
template<class Iter>
void f(Iter first, Iter last){...}