Scenario (see code below for reference):
The original (Base) implementation must have func1() returning a list. Internally it makes calls to merge and splice.
The subsequent (Derived) implementation must have func1() returning a vector. It needs random access.
func2() is common to both implementations and simply needs a forward iterator.
#include <iostream>
#include <list>
#include <vector>
class Base {
protected:
virtual void func1(std::list<int>& l /* out parameter */) {
// This must use list. Calls merge and splice.
std::cout << "list version of func1 in base\n";
}
virtual void func1(std::vector<int>& v) {
// This should never be called, but code won't compile without it.
std::cout << "vector version of func1 in base\n";
}
template <class T> void func2(T container) {
typename T::const_iterator it = container.cbegin();
// Iterate and perform work. Common to both Base and Derived.
std::cout << "func2 in base\n";
}
template <class T> void processHelper() {
T container;
func1(container);
func2<T>(container);
}
public:
virtual void process() {
processHelper<std::list<int> >();
}
};
class Derived : public Base {
protected:
virtual void func1(std::vector<int>& v /* out parameter */) {
// This must use a random access container.
std::cout << "Vector version of func1 in derived\n";
}
public:
virtual void process() {
processHelper<std::vector<int> >();
}
};
int main(int argc, const char * argv[])
{
std::vector<int> var;
Derived der;
der.process();
//std::list<int> var;
//Base bs;
//bs.process();
std::cout << "done\n";
}
Goals:
No (or minimal) duplication (cut and paste) of code.
Avoid compiling with Boost. (Haven't needed it yet. Don't want to for this.) This rules out a couple of any_iterator implementations.
Question:
Is there a better OO design in C++ to achieve what I am doing? I have reasons for not wanting to turn my list into a vector or vice versa before returning from func1(). Specifically, the list is large at this point and I'd prefer to not incur the extra copy. I could have designed the func1()'s to return an opaque_iterator http://www.mr-edd.co.uk/code/opqit but was hesitant to bring in an unknown header file.
In any case, the question took on an academic life of it's own. This problem is so easy in Java since the collections implement common interfaces, but seems challenging in C++. Particularly bothered by the ugliness of having to implement Base::func1(std::vector& v) just to get the code to compile even though there's no execution path that will ever call this function. Hoping there's an easier way and I'm just not seeing a more straightforward solution.
The C++ way is working with iterators. You can do pretty much anything with the standard algorithms. The library is on intentionally separated on
Containers <--> Iterators <--> Algorithms
Containers define iterators (that are basically glorified pointers) and algorithms work with iterators. Containers and algorithms are unkown to each other.
Normally you would pass a couple of iterators (usually container.begin() and container.end()) and the algorithm will be implemented in terms of those.
Have a look at the standard algorithms and see if you can come up with a solution on what you want to do. To do that your function should be templated on iterators rather than on containers.
Hope that helps.
The generic way would be to have func1 take an output iterator:
template<class OutputIterator> void func1(OutputIterator &&out) {
:
You then call it with a back_insert_iterator on the container you want to use for output:
std::list<int> tmp;
obj->func1(std::back_inserter(tmp));
I ended up finding lots of questions along the same lines, some on Stack Overflow. So maybe this is a duplicate. If so, apologies. Here are some relevant links:
How to write a function that takes an iterator or collection in a generic way?
Generic iterator
http://www.artima.com/cppsource/type_erasure.html
I ended up going with a simple type erasure approach modeled after this article: http://www.cplusplus.com/articles/oz18T05o/ I can't claim to understand everything that's going on here, but it does work. The only downside is that I had to wrap the iterator API in my Container class and return all primitives and well-known classes rather than just expose the underlying iterator directly. So my Container wrapper is not very reusable.
I have posted the code I wrote below in the hope that it will be useful to someone else:
#include <iostream>
#include <list>
#include <vector>
// Type erasure for returning different std containers based off of: http://www.cplusplus.com/articles/oz18T05o/
class Container {
protected:
class IContainer {
public:
virtual ~IContainer() {}
virtual void setBegin() = 0;
virtual bool isEnd() = 0;
virtual int get() = 0;
virtual void next() = 0;
};
template <typename T> class ContainerModel : public IContainer {
public:
ContainerModel(const T& container_) : m_container(container_) {}
virtual ~ContainerModel() {}
virtual void setBegin() {
m_cit = m_container.cbegin();
}
virtual bool isEnd() {
return (m_cit == m_container.cend());
}
virtual int get() {
return *m_cit;
}
virtual void next() {
++m_cit;
}
protected:
T m_container;
typename T::const_iterator m_cit;
};
std::shared_ptr<IContainer> m_spContainer;
public:
template <typename T> Container(const T& t_) : m_spContainer(new ContainerModel<T>(t_)) {}
virtual ~Container() {}
virtual void setBegin() {
m_spContainer->setBegin();
}
virtual bool isEnd() {
return m_spContainer->isEnd();
}
virtual int get() {
return m_spContainer->get();
}
virtual void next() {
m_spContainer->next();
}
};
class Base {
protected:
virtual Container func1() {
std::cout << "list version of func1 in base\n";
std::list<int> l;
// Do lots of stuff with lists. merge(), splice(), etc.
return Container(l);
}
virtual void func2(const Container& container) {
// Iterate using setBegin(), get(), next() and isEnd() functions.
std::cout << "func2 in base\n";
}
public:
virtual void process() {
Container container = func1();
func2(container);
}
};
class Derived : public Base {
protected:
virtual Container func1() {
std::cout << "Vector version of func1 in derived\n";
std::vector<int> v;
// Do lots of stuff with vector's random access iterator.
return Container(v);
}
};
int main(int argc, const char * argv[])
{
Derived der;
der.process();
//Base bs;
//bs.process();
std::cout << "done\n";
}
Related
I am fairly new to C++ and templates. I dont expect the reason why it doesnt work to be very complex, but I'm just not getting it.
void print(vector<> v) {
return;
}
does not compile with the error
error: wrong number of template arguments (0, should be at least 1)
however
void print(vector<int> v) {
return;
}
doesn't yield such an error.
Why is that?
You must make your function template to accept more than one type:
template <typename T>
void print(vector<T> v) {
return;
}
If you are coming from another language (I think Java uses the syntax you proposed?), I suggest getting a good C++ book to learn from. It's going to be much less painful to learn properly from start than trying to apply your knowledge from other languages in C++.
If you need to store elements of different types, you should look into polymorphism and class hierarchies. For example, if you had two different classes A and B, and needed a vector to hold either of those, you could make sure that they share a common base class.
You could then store pointers or references to such objects in one and the same vector, like so (using smart pointers in this case):
#include <iostream>
#include <memory>
#include <vector>
class Base {
public:
virtual ~Base() {}
virtual void print() = 0;
};
using BasePtr = std::shared_ptr<Base>;
class A : public Base {
public:
virtual void print() override { std::cout << "I'm an A" << std::endl; }
};
class B : public Base {
public:
virtual void print() override { std::cout << "I'm a B" << std::endl; }
};
void print(const std::vector<BasePtr>& v) {
for (auto&& i : v)
i->print();
}
int main()
{
std::vector<BasePtr> v;
v.push_back(std::make_shared<A>()); /* create and add an element of type A */
v.push_back(std::make_shared<B>()); /* create and add an element of type B */
print(v);
}
(Also, note that I'm passing the vector type as const reference, otherwise it would be copied before being passed into the function.)
I am trying to implement a list data structure in C++.
I want to define a list interface which would be later inherited by implementation such as ArrayList or LinkedList.
I'd like to be able to use it like
List<int>* testList = new LinkedList<int>;
So i've tried to implement full virtual templated class but then realized i cannot mix virtual and templated methods. I tried much different ways and im encountering problems all the way.
Whats the best way to do it ?
Edit (problematic code). I'm trying to make interface to look like this:
template<typename T>
class List {
public:
virtual void add(T*) {};
virtual void remove(unsigned int) = 0;
virtual unsigned int size() = 0;
virtual void get(unsigned int) = 0;
virtual ~List();
};
and then im trying to implement it here:
template<typename T>
class LinkedList : public List<T> {
/* some stuff */
public:
LinkedList();
virtual unsigned int size();
virtual void add(T*); // the problem i guess
virtual void remove(unsigned int);
virtual void get(unsigned int);
virtual ~LinkedList();
};
So i've tried to implement full virtual templated class but then
realized i cannot mix virtual and templated methods.
Your example code indicates, that you don't want virtual, templated methods, but a template class that has virtual methods. The former is not allowed, the latter IS (this is a common point of confusion).
So this is perfectly valid code:
#include <iostream>
#include <memory>
template<class T>
class List{
public:
virtual void push()=0;
virtual void pop()=0;
virtual ~List()=default;
};
template<class T>
class LinkedList: public List<T>{
public:
virtual void push() {
std::cout << "Pushed element to Linked List"<< std::endl;
}
virtual void pop() {
std::cout << "Poped element from Linked List"<< std::endl;
}
};
template<class T>
class ArrayList: public List<T>{
public:
virtual void push() {
std::cout << "Pushed element to ArrayList"<< std::endl;
}
virtual void pop() {
std::cout << "Poped element from ArrayList"<< std::endl;
}
};
int main()
{
List<int>* list1=new LinkedList<int>();
List<int>* list2=new ArrayList<int>();
// And this is how you would actually create objects on the heap nower days:
std::unique_ptr<List<int>> list3=std::make_unique<LinkedList<int>>();
list1->push();
list2->push();
list3->push();
list1->pop();
list2->pop();
list3->pop();
delete(list1);
delete(list2);
//no delete(list3) needed
return 0;
}
Besides that, I don't know, why you want to do that. C++ has a perfectly fine implementation of a linked list and an implementation of and array/vector and thanks to iterator based semantic, you can run (almost) any algorithm on them without the need for a common base class.
I apologize, if this sounds harsh, but it looks like you are comming from Java and trying to learn C++. But instead of learning C++, you try to write wrappers, that make C++ look like java. While this is certainly possible most of the time (as long as you don't forget, that standard c++ doesn't have a garbage collector) its often not a sensible approach. whether that holds true in your case of course depends on your application. But my recommendation ist to learn about iterators and the standard library algorithms.
Templated virtual member functions are not supported in C++ but I have a scenario where it would be ideal. Im wondering if someone has ideas for ways to accomplish this.
#include <iostream>
class Foo {
public:
virtual void bar(int ){}
// make a clone of my existing data, but with a different policy
virtual Foo* cloneforDB() = 0;
};
struct DiskStorage {
static void store(int x) { std::cout << "DiskStorage:" << x << "\n"; }
};
struct DBStorage {
static void store(int x) { std::cout << "DBStorage:" << x << "\n"; }
};
template<typename Storage>
class FooImpl : public Foo {
public:
FooImpl():m_value(0) {}
template<typename DiffStorage>
FooImpl(const FooImpl<DiffStorage>& copyfrom) {
m_value = copyfrom.m_value;
}
virtual void bar(int x) {
Storage::store(m_value);
std::cout << "FooImpl::bar new value:" << x << "\n";
m_value = x;
}
virtual Foo* cloneforDB() {
FooImpl<DBStorage> * newfoo = new FooImpl<DBStorage>(*this);
return newfoo;
}
int m_value;
};
int main()
{
Foo* foo1 = new FooImpl<DiskStorage>();
foo1->bar(5);
Foo* foo2 = foo1->cloneforDB();
foo2->bar(21);
}
Now if I want to clone the Foo implmemetation, but with a different Storagepolicy, I have to explicitly spell out each such implementation:
cloneforDB()
cloneforDisk()
A template parameter would have simplified that.
Can anyone think of a cleaner way to do this?
Please focus on the idea and not the example, since its obviously a contrived example.
Usually if you want to use a virtual template method, it means that something is wrong in the design of your class hierarchy. The high level reason for that follows.
Template parameters must be known at compile-time, that's their semantics. They are used to guarantee soundness properties of your code.
Virtual functions are used for polymorphism, ie. dynamic dispatching at runtime.
So you cannot mix static properties with runtime dispatching, it does not make sense if you look at the big picture.
Here, the fact that you store something somewhere should not be part of the type of your method, since it's just a behavioral trait, it could change at runtime. So it's wrong to include that information in the type of the method.
That's why C++ does not allow that: you have to rely on polymorphism to achieve such a behavior.
One easy way to go would be to pass a pointer to a Storage object as an argument (a singleton if you just want one object for each class), and work with that pointer in the virtual function.
That way, your type signature does not depend on the specific behavior of your method. And you can change your storage (in this example) policy at runtime, which is really what you should ask for as a good practice.
Sometimes, behavior can be dictated by template parameters (Alexandrescu's policy template parameters for example), but it is at type-level, not method level.
Just use templates all the way:
class Foo {
public:
virtual void bar(int ){}
template <class TargetType>
Foo* clonefor() const;
};
class FooImpl { ... };
template
inline <class TargetType>
Foo* Foo::clonefor() const
{
return new FooImpl<TargetType>(*this);
}
Now call it:
int main()
{
Foo* foo1 = new FooImpl<DiskStorage>();
foo1->bar(5);
Foo* foo2 = foo1->clonefor<DBStorage>();
foo2->bar(21);
}
A trick I have sometimes used to get around this issue is this:
template<typename T>
using retval = std::vector<T const*>;
struct Bob {};
// template type interface in Base:
struct Base {
template<typename T>
retval<T> DoStuff();
virtual ~Base() {};
// Virtual dispatch so children can implement it:
protected:
virtual retval<int> DoIntStuff() = 0;
virtual retval<double> DoDoubleStuff() = 0;
virtual retval<char> DoCharStuff() = 0;
virtual retval<Bob> DoBobStuff() = 0;
};
// forward template interface through the virtual dispatch functions:
template<> retval<int> Base::DoStuff<int>() { return DoIntStuff(); }
template<> retval<double> Base::DoStuff<double>() { return DoDoubleStuff(); }
template<> retval<char> Base::DoStuff<char>() { return DoCharStuff(); }
template<> retval<Bob> Base::DoStuff<Bob>() { return DoBobStuff(); }
// CRTP helper so the virtual functions are implemented in a template:
template<typename Child>
struct BaseHelper: public Base {
private:
// In a real project, ensuring that Child is a child type of Base should be done
// at compile time:
Child* self() { return static_cast<Child*>(this); }
Child const* self() const { return static_cast<Child const*>(this); }
public:
virtual retval<int> DoIntStuff() override final { self()->DoStuff<int>(); }
virtual retval<double> DoDoubleStuff() override final { self()->DoStuff<double>(); }
virtual retval<char> DoCharStuff() override final { self()->DoStuff<char>(); }
virtual retval<Bob> DoBobStuff() override final { self()->DoStuff<Bob>(); }
};
// Warning: if the T in BaseHelper<T> doesn't have a DoStuff, infinite
// recursion results. Code and be written to catch this at compile time,
// and I would if this where a real project.
struct FinalBase: BaseHelper<FinalBase> {
template<typename T>
retval<T> DoStuff() {
retval<T> ret;
return ret;
}
};
where I go from template-based dispatch, to virtual function dispatch, back to template based dispatch.
The interface is templated on the type I want to dispatch on. A finite set of such types are forwarded through a virtual dispatch system, then redispatched at compile time to a single method in the implementation.
I will admit this is annoying, and being able to say "I want this template to be virtual, but only with the following types" would be nice.
The reason why this is useful is that it lets you write type-agnostic template glue code that operates on these methods uniformly without having to do stuff like pass through pointers to methods or the like, or write up type-trait bundles that extract which method to call.
I'm trying to implement an event manager based on the linked code in the top answer here:
Game Objects Talking To Each Other
However I'm getting an error when I try to register the callbacks.
I'm sure it has to do with the typedef, and I admit I'm not sure how it works exactly, but it is in the exact same form in the linked code.
The B class should be inherriting from the Interface, so why is the type different?
I've condensed the code into the smallest example below.
#include <iostream>
class Interface;
typedef void (Interface::*Callback)(void *data);
class Interface
{
public:
void Register (Callback func);
};
void Interface::Register(Callback func)
{
std::cout << "Register" << std::endl;
}
class B : public Interface
{
public:
B();
void Echo(void *data);
};
B::B()
{
Register( (Callback)Echo );
}
void B::Echo(void *data)
{
std::cout << "Echo" << std::endl;
}
int main()
{
B b;
return 0;
}
Here's the error I get under g++ 4.6.1:
test.cpp: In constructor ‘B::B()’:
test.cpp:31:22: error: argument of type ‘void (B::)(void*)’ does not match ‘Callback {aka void (Interface::*)(void*)}’
Could anyone please explain what I'm doing wrong?
Thanks
As #Kerrek correctly pointed out, Echo is not a member of Interface, therefore B::Echo doesn't qualify as Interface::*Callback. But you can use a template to accomplish that, e.g.:
template <class T> class Interface {
public:
typedef void (T::*Callback)(void *data);
void Register(Callback func) {
std::cout << "Register" << std::endl;
}
// ...
};
class B : public Interface<B> {
public:
B() {
Register(&B::Echo);
}
void Echo(void *data) {
// Do something
}
};
I think you might be better off using std::function (c++11) or boost::function (c++03+boost)
#include <iostream>
class Interface;
typedef void (Interface::*Callback)(void *data);
class Interface
{
public:
std::function<void(void*)> register;
Interface(std::function<void(void*)> register_)
: register(register_) //intializer list
{}
virtual ~Interface(){} //put me in
};
void Interface::Register(Callback func)
{
std::cout << "Register" << std::endl;
}
class B : public Interface
{
public:
B();
void Echo(void *data);
};
B::B()
: Interface( std::bind(B::Echo, this) )
{}
void B::Echo(void *data)
{
std::cout << "Echo" << std::endl;
}
Although why you aren't using pure virtuals is beyond me
class Interface
{
public:
virtual void Echo(void*)=0;
};
void B::Echo(void *data) //implements Echo
{
std::cout << "Echo" << std::endl;
}
call interface->echo will call the child
if you need performance then use the
http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
And be very careful with void* they are generally considered bad.
EDIT ADDRESSING POINT IN COMMENTS: non pure virtuals
class Interface
{
public:
virtual ~Interface(){} //put me in
virtual void echo(void*){} //if implementation is not extended it will do nothing.
//others
};
This ins't Java, interfaces aren't a thing defined by the language. This way you can have an interface which you can pick can choose which part to implement, if a callback doesn't concern your class, then just don't implement it.
void* are bad for a whole host of reasons. from C++ FAQ
avoid void* (keep them inside low-level functions and data structures
if you really need them and present type safe interfaces, usually
templates, to your users)
http://www2.research.att.com/~bs/bs_faq.html
search on "void*"
but basically void* bypass all the type safety that C++ went out of it's way adding. It is a hack in C to make up for the fact that it doesn't have any polymorphism or generic code.
(Related to a previous unanswered question I asked). I want to implement a function which can be called only with vectors of related classes as parameter.
For eq
if we have
class A;
class B: public A;
class C: public A;
class D
then it should be possible to call function with vector<A*>,vector<B*> or
vector <C*> but not vector <D*>
Any suggestions
I guess you already tried to create a method like
void doSomething(std::vector<A*>& things)
{
}
and tried do pass
std::vector<B*> bList = ...;
doSomething(bList);
right?
Why does the compiler complain? Because it would not make sense. Consider that doSomething() tries to do
things.push_back(new C());
This cannot work as "things" is actually a std::vector<B*>. However, if it were std::vector<A*>, push_back would work.
So what can we learn from this? What you're trying only makes sense if you only read from the vector, however, vector is not a read-only container.
A simple wrapper shows a possible solution (the wrapper can be adjusted to your needs, of course). However, I have to point out that the use of virtual methods might lead to performance penalties.
class A {};
class B : public A {};
template <class Base>
class AbstractVectorWrapper
{
public:
virtual size_t size() const = 0;
virtual Base* getElementAt(int index) const = 0;
};
template <class Base, class Derived>
class VectorWrapper : public AbstractVectorWrapper<Base>
{
private:
std::vector<Derived*> m_vector;
public:
explicit VectorWrapper(std::vector<Derived*> const& vector)
: m_vector(vector)
{
}
virtual size_t size() const
{
return m_vector.size();
}
virtual Base* getElementAt(int index) const
{
return m_vector[index];
}
};
void doSomething(AbstractVectorWrapper<A> const& wrapper)
{
for (size_t i=0;i<wrapper.size();i++)
{
A* a = wrapper.getElementAt(i);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<A*> as;
std::vector<B*> bs;
doSomething(VectorWrapper<A,B>(bs));
doSomething(VectorWrapper<A,A>(as));
return 0;
}
Is duck-typing good enough for you? Consider this code
template <class T>
void my_function (std::vector <T*> const &values) {
// Use features of A* here
}
This will fail to compile if you use features that pointers to T do not support. By using features of A I think it should be guaranteed that pointers to B and C will also work as expected. However, it would be possible to call this function with vectors of D *, provided D's interface complies with what my_function tries to do.