I am trying to implement a multi-type container in C without using std::any
, std::variant
, boost::any
, etc. The add()
function adds new objects (int
, string
, or other Structure
s) by wrapping them in the template element class and storing as Structure
pointers:
using StructPtr = std::shared_ptr<Structure>;
class Structure{
public:
Structure() = default;
Structure(const Structure& oldStruct);
Structure operator = (Structure otherStruct);
bool operator == (const Structure& otherStruct);
template<class T>
void add(T obj){
elements.emplace_back(std::make_shared<Element<T>>(obj));
}
void print(std::ostream& out);
std::vector<StructPtr> elements;
};
template<class T>
class Element : public Structure{
public:
Element() = default;
Element(T _element) : element(_element) { }
Element( Element& oldElement){
element = oldElement.element;
}
T element;
};
I have a print function that takes in an element and prints it:
template<class T>
void printElement(std::ostream& out, const Element<T>& element){
printElement(out, element.element); //this functionality has been provided already.
}
I want to go through each element in the vector and pass it to this print function. However, since they are stores as StructPtr
s, I do not know how to cast them into this templated Element
class (I cannot use dynamic_cast
).
This is what I tried:
template<class T>
void printElement(std::ostream& out, const std::vector<StructPtr>& elements){
for(auto element : elements){
auto elementDerived = static_cast<Element<T>>(*element);
printElement(out, elementDerived);
}
}
void printElement(std::ostream& out, const Structure& s){
printElement(out, s.elements);
}
But this gives an error:
no instance of overloaded function "printElement" matches the argument listC/C (304)
task01.cpp(64, 5): argument types are: (std::__1::ostream, const std::__1::vector<StructPtr, std::__1::allocator<StructPtr>>)
So, my main question is, how do I call:
template<class T>
void printElement(std::ostream& out, const Element<T>& element)
on each element of the vector?
CodePudding user response:
You can't perform a static_cast
inside of printElement()
since you don't know what to cast to (dynamic_cast
would have helped you with that), so the only solution is to make Structure::print()
be virtual
and have Element
override it, eg:
class Structure{
public:
...
virtual void print(std::ostream& out) const {
printElement(out, elements);
}
...
};
template<class T>
class Element : public Structure{
public:
...
void print(std::ostream& out) const override {
printElement(out, element);
}
...
};
void printElement(std::ostream& out, const std::vector<StructPtr>& elements){
for(auto element : elements){
element->print(out);
}
}