Reputation: 87
I need to store objects of exactly two types in a vector, the both types have almost nothing in common.
After storing them in the vector, I want to iterate over that vector and perform an action, depending on the type.
my thoughts so far:
Polymorphism. Overkill, and wouldn't help me much, as I probably would do this:
if(dynamic_cast<T1>() != nullptr) {
...
} else {
...
}
Merge both types (methods and fields) and add a boolean, representing if its type 1 or 2.
Both patterns seem totally clumsy to me, there is propably a total simple solution, I simply don't see.
The first type is something like this :
struct PatternMatch {
int length;
int indexInDict;
}
The second one:
struct NoMatch {
std::string rawChars;
}
Upvotes: 1
Views: 154
Reputation: 50540
If you know that you have only two types and this number won't grow in future, a C-ish tagged union is enough and easy to use:
struct PatternMatch {
int length;
int indexInDict;
};
struct NoMatch {
std::string rawChars;
};
struct TaggedUnion {
enum { MATCH, NO_MATCH } flag;
union {
PatternMatch match;
NoMatch noMatch;
};
};
Now, you can create a vector of TaggedUnion
s and check the flag
data member to find out the actual type of each element.
Upvotes: 1
Reputation: 93274
Use boost::variant
or any other "stack-based discriminated union container". I also suggest visiting the variant using lambdas.
// Either `A` or `B`.
using my_type = boost::variant<A, B>;
std::vector<my_type> my_vec;
// ...`emplace_back` stuff into `my_vec`...
auto visitor = make_lambda_visitor<void>(
[](A&) { /* do something with A */ },
[](B&) { /* do something with B */ }
);
for(auto& x : my_vec)
{
boost::apply_visitor(visitor, x);
}
Note that C++17 will have std::variant
.
Upvotes: 5