C++ pass generic vector as function parameter - c++

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.)

Related

Multi-inheritance with interfaces type casting on pointers for using with std::list

I come from Java (OOP) background. I made a simple class to illustrate my problem:
#include <list>
#include <string>
#include <iostream>
// classes
class InterfaceA
{
public:
virtual std::string functionA();
};
class InterfaceB
{
public:
virtual std::string functionB();
};
class DerivedAB : public InterfaceA, public InterfaceB
{
public:
std::string functionA()
{
return "I'm a A object";
}
std::string functionB()
{
return "I'm a B object";
}
};
// functions
void doStuffOnListOfA(std::list<InterfaceA*> aElements)
{
std::cout << "Print list of A" << std::endl;
for (InterfaceA* const& a : aElements)
{
std::cout << a->functionA() << std::endl;
}
};
int main()
{
std::list<DerivedAB*> derivedABs;
doStuffOnListOfA(derivedABs);
return 0;
}
I have two simple virtual classes InterfaceA and InterfaceB and a class DerivedAB that multi-inherits the two first virtual classes.
Furthermore, I then create a list of pointers of DerivedAB (std::list<DerivedAB *>) and wish to use this list with a function designed to work on a list of InterfaceA-derived objects. But I get an error:
(base) ❮ onyr ★ kenzae❯ ❮ multi_inheritance_type_convertion❯❯ make
g++ -c -o main.o main.cpp
main.cpp: In function ‘int main()’:
main.cpp:54:32: error: could not convert ‘derivedABs’ from ‘std::__cxx11::list<DerivedAB*>’ to ‘std::__cxx11::list<InterfaceA*>’
doStuffOnListOfA(derivedABs);
I have obviously a type casting error. I have read many articles on Stack Overflow about the different casting in C++ as well as on Multi-Inheritance, but my brain refuses to give me the answer.
Edits:
I said an erroneous statement:
"However I'm pretty sure such a code would work in Java..."
Apparently I'm missing an important concept about type inheritance...
C++ is far different from Java!
I have obviously a type casting error.
You are right about this (aka. type mismatch)! The std::list is a standard template container which gives you a concrete type, when you instantiate with a template argument.
That means, the std::list<InterfaceA*> is different from std::list<DerivedAB *>.
This is exactly the compiler tells you:
error: could not convert
from ‘std::__cxx11::list<DerivedAB*>’ ----> i.e. std::list<DerivedAB*>
to ‘std::__cxx11::list<InterfaceA*>’ ----> i.e std::list<InterfaceA*>
doStuffOnListOfA(derivedABs); ----> at the function call
You can not implicitly(i.e. compiler will not) convert to one another.
You need to cast each element of the derivedABs to base pointers or (in your case) make the doStuffOnListOfA as template function:
template<typename T>
void doStuffOnListOfA(std::list<T*> aElements)
{
std::cout << "Print list of A" << std::endl;
for (InterfaceA* a : aElements)
{
std::cout << a->functionA() << std::endl;
}
};
To make sure that, one use the above only for std::list<derived from InterfaceA and B>, you may can (optionally) SFINAE the template function:
#include <type_traits> // std::is_base_of
template<typename T>
constexpr bool isBaseOfInterfaces = std::is_base_of_v<InterfaceA, T> && std::is_base_of_v<InterfaceB, T>;
template<typename T>
auto doStuffOnListOfA(std::list<T*> aElements)
-> std::enable_if_t<isBaseOfInterfaces<T>, void>
{
// ... code
};
That being said,
You need to look into the smart pointers (such as std::unique_ptr, std::shared_ptr) rather than using raw pointers (manual memory management), by which you can handle the memory management smartly.
You might want to add the virtual destructor in your base classes for a defined behavior. See here for more: When to use virtual destructors?
Here is (the complete demo)

How do I put items into a vector which has a type of a templated super class

Assume I have the following 2 classes Super and Deriv where Deriv is a subclass of Super.
Super and Deriv are both templated classes. I want to create a vector of type Super<?>. Where the ? signifies any type. Currently I have come up with this:
#include <iostream>
#include <vector>
template <typename T>
class Super {
public:
T val;
Super(T val) : val(val) {};
};
template <typename T>
class Deriv : public Super<T> {
public:
Deriv(T val) : Super<T>(val) {};
};
int main() {
std::vector<Super*> a;
a.push_back(new Deriv<int>(1));
a.push_back(new Deriv<float>(1.0f));
std::cout << a[0]->val << std::endl;
return 0;
}
Of course this does not work because std::vector<Super*> needs a template type like std::vector<Super<int>*>. However the problem with this is I can only add items to the vector of type Super<int>* and not Super<float>*.
How can I alter this code to allow me to add a Super type or it's derivatives to a vector which has any template type like int, float, short etc?
Not sure if this can solve your problem, but it might give you some ideas. The basic idea here is to make a super class for all kinds of T. For fundamental data types, wrapper classes are needed.
#include <iostream>
#include <cstdio>
#include <vector>
#include <string>
class SuperT {
public:
virtual std::string AccessData() = 0;
};
class IntWraper : public SuperT {
public:
IntWraper(int i) : val(i) { };
virtual std::string AccessData() { return std::to_string(val); };
private:
int val;
};
class FloatWraper : public SuperT {
public:
FloatWraper(float f) : val(f) { };
virtual std::string AccessData() { return std::to_string(val); };
private:
float val;
};
class RealSuper {
public:
virtual std::string DoSomething() = 0;
};
template <typename T>
class Super : public RealSuper {
public:
T* wraper_val_;
Super(T* w_val) : wraper_val_(w_val) { };
~Super() { if(wraper_val_) delete wraper_val_; };
virtual std::string DoSomething() { return wraper_val_->AccessData(); }
};
template <typename T>
class Deriv : public Super<T> {
public:
Deriv(T* w_val) : Super<T>(w_val) {};
};
int main() {
std::vector<RealSuper*> a;
a.push_back(new Deriv<IntWraper>(new IntWraper(1)));
a.push_back(new Deriv<FloatWraper>(new FloatWraper(1.0f)));
std::cout << a[0]->DoSomething() << std::endl;
std::cout << a[1]->DoSomething() << std::endl;
return 0;
}
This
std::vector<Super*> a;
Is wrong.
There is no type named Super in your code. Yes, you declared something named "Super", but it's not a class, it's a class template.
The name of the feature says it all. It's a template. The compiler will use Super to generate new types at compile time.
For example, Super<int> Refer to the class generated by the compiler when filling the hole T in the Super template.
So why a[0]->val cannot possibly work? Well, imagine this:
template<>
struct Super<std::string> {
std::string my_val;
};
We specialize Super so when instantiated with std::string, it no longer have the val member, but the my_val member.
Now, what do you expect this code to do?
std::vector<Super*> a;
a.push_back(new Deriv<std::string>);
std::cout << a[0]->val << std::endl;
Quite puzzling isn't it? You'd need a compilation error at runtime. Since the existence (or non existence) of variable is determined at compile time, it's not possible.
Now how can we solve your problem?
In your case, it would be as simple as adding an interface above Super, and exposing functions that implements behaviors needed to do your calculations:
struct Interface {
void print(std::ostream) const = 0;
bool lessThan(double) const = 0;
};
template <typename T>
struct Super : Interface {
T val;
Super(T val_) : val{val_} {};
// We implement the needed behavior.
void print(std::ostream o) const override {
o << val << std::endl;
}
// Example of calculation
bool lessThan(double rhs) const override {
return val < rhs;
}
};
Now you can do:
std::vector<Interface*> a;
// ...
a[0]->print(std::cout);
a[0]->lessThan(3.7);
Create a new class RealSuper that cache the type is a possible workaround.
It is not perfect, but I am afraid that it can't be much better than this :-
class RealSuper{ //<-- new class
public: enum TYPE{ type_int, type_float, type_notIni }; // (yes, it is awkward)
TYPE typee = type_notIni;
};
template <typename T> class Super : public RealSuper { //<-- modify
public: T val;
Super(T val) : val(val) {
if( std::is_same<T, int>::value ){
typee = type_int;
}else if( std::is_same<T, float>::value ){
typee = type_float;
}
};
};
template <typename T> class Deriv : public Super<T> {
public: Deriv(T val) : Super<T>(val) {};
};
int main() {
std::vector<RealSuper*> a;
a.push_back(new Deriv<int>(1));
a.push_back(new Deriv<float>(1.0f));
for(auto ele: a){
switch( ele->typee ){
case RealSuper::TYPE::type_int: {
int value=static_cast<Super<int>*>(ele)->val;
std::cout << value << std::endl;
};break;
case RealSuper::TYPE::type_float :{
float value=static_cast<Super<float>*>(ele)->val;
std::cout << value << std::endl;
};break;
}
}
return 0;
}
live demo
Here is another demo to show an approach using the virtual function.
C++ does not have the feature you are asking for (I believe it is a kind of reification). This means you cannot store arbitrary types in location one, then specify arbitrary operations in a completely unrelated source file in location two, then apply the operations to the data in location three.
There are many problems you can solve that are close to what you are asking for: Restrict what operations you want to do at location two, or restrict what types you store at location one, and the problem can be solved. Alternatively, restrict what type x operation pairs you support at location three.
Note that composition of the restricted set of operations can also work.
In theory you can embed a full compiler or interpreter in a C++ binary, compile code and dynamically load it. (This is basically how C#/Java manage reification). This is rather impractical for most problems. The language provides no support for this, but this is C++, you can do anything (write a Java/C# compiler even).
With no information about the underlying problem you need to solve, I cannot tell you which of the above is the correct approach.
This is the reason why "if I had X I coukd solve Y, but I cannot figure out X. I know, I'll just ask stack overflow how to do X!" is known as an X/Y problem. We can probably solve Y, but you asked about X which woukd solve Y without even describing Y. Feel free to post the Y problem and ask about it. Use the [ask a question] button above.
Restrict what types you handle at storage:
Store a std::variant. Use std::visit. Or write your own or use boost::variant.
Restrict what operations to perform:
Use type erasure to generate the per-type operation when you store the type.
Restrict the operation-type pairs at point of call:
Use RTTI to exctract what type is stored, have a large switch switch that then uses solution one.

How to handle different C++ containers generically?

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";
}

Callback argument type does not match in inherited class

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.

Technique for Using Templates and Virtual Functions

A while back I learned about the Curiously Recurring Template Pattern (http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern), and it reminded me of a technique I had used to implement an event queue cache.
The basic idea is that we take advantage of a Base class pointer to store a container of homogeneous pointer types. However because the Derived class is a template class, which stores an item of type T, what we are really storing is a list of heterogeneous types.
I was curious if anyone has seen this technique, which is perhaps interesting, and if so if anyone has named it? Anyone care to critique it? Is there a better way to achieve my end here?
Thanks.
#include <iostream>
#include <algorithm>
#include <functional>
#include <list>
#include <string>
class Base
{
public:
Base(){}
virtual ~Base(){}
virtual void operator()() = 0;
};
template<typename C, typename T>
class Derived : public Base
{
public:
Derived(C* c, T item) : consumer_(c), item_(item) {}
virtual void operator()()
{
consumer_->consume(item_);
}
C* consumer_;
T item_;
};
class Consumer
{
bool postpone_;
std::list<Base*> cache_;
public:
Consumer() : postpone_(true)
{
}
void pause()
{
postpone_ = true;
}
void resume()
{
postpone_ = false;
const std::list<Base*>::iterator end = cache_.end();
for ( std::list<Base*>::iterator iter = cache_.begin();
iter != end;
++iter )
{
Base* bPtr = *iter;
bPtr->operator()();
delete bPtr;
}
cache_.clear();
}
void consume(int i)
{
if ( postpone_ )
{
std::cerr << "Postpone int.\n";
cache_.push_back(new Derived<Consumer, int>(this, i));
}
else
{
std::cerr << "Got int.\n";
}
}
void consume(double d)
{
if ( postpone_ )
{
std::cerr << "Postpone double.\n";
cache_.push_back(new Derived<Consumer, double>(this, d));
}
else
{
std::cerr << "Got double.\n";
}
}
void consume(char c)
{
if ( postpone_ )
{
std::cerr << "Postpone char.\n";
cache_.push_back(new Derived<Consumer, char>(this, c));
}
else
{
std::cerr << "Got char.\n";
}
}
};
static Consumer consumer;
void destroy(Base* object)
{
delete object;
}
int main()
{
// Consumer is registered with something that sends events out to lots
// of different consumer types (think observer pattern). Also in the non-toy
// version consumer isn't being passed PODs, but various Event types.
consumer.consume(0);
consumer.consume(0.1f);
consumer.consume('x');
consumer.resume();
}
The output is:
Postpone int.
Postpone double.
Postpone char.
Got int.
Got double.
Got char.
What you are using is plain polymorphism, as Stephen points out in his comment. While you store different objects internally in the container, you are limited to using the interface defined in Base. That is, of course, unless you intend to add type checking and downcasts to actually retrieve the values. There is just a limited amount of things that you can do with unrelated objects.
Depending on what you are actually wanting to achieve you might consider using other solutions like boost::any/boost::variant if what you want is to actually store unrelated types (in the few cases where this makes sense --cells in a spreadsheet, for example).
anyone has named it?
I think it is an adapter pattern implemented without using inheritance from T.
Anyone care to critique it?
YOu could have used short template function instead of this class. Or you could use template function that returns template class. Template function can automatically guess required types - sou you could omit <> and do less typing.
Nice.
You're utilizing compiler's power to generate templated series of derived classes and it's actually cool that you can mix plain derived classes
(written by yourself) with template-specialized derived classes and with compiler-generated ones
(built as result of template instantiation).
class Base { ... };
template <typename Y> class Derived1 : public Base { ... };
template <specialization>
class Derived1 : public Base { ... };
class Derived2 : public Base { ... };
This could be useful, but it doesn't somehow extend the polymorphism term, because you're still limited to the Base class interface.
Also, you could write a plain factory which would have some templated method for generating subclasses and use it to avoid writing new Derived1<std::string>..., but write something like
std::string a;
Base* base = Factory.Create(a)