The Partridge Family were neither partridges nor a family. Discuss.
-
albinopapa
- Posts: 4373
- Joined: February 28th, 2013, 3:23 am
- Location: Oklahoma, United States
Post
by albinopapa » March 30th, 2020, 1:18 am
Just wanted to say it's a shame you aren't using std::variant. It's a pretty decent alternative to dynamic polymorphism. Here's a sample of finding an object by type using it:
Code: Select all
#include <variant>
class B0
{
};
class B1
{
};
class A
{
public:
// List each sub-class type in the template parameter list of std::variant
// Here is use 'using' to alias the type so I don't have to retype the whole thing elsewhere
using tvar = std::variant<B0, B1>;
public:
// Here, the A constructor can take in any type listed in the std::variant
// template parameter list and initialize the variant member with it
template<typename T> A( T const& var_ ) :var( var_ ) {}
public: // vars
tvar var;
};
// Free function for finding the first item of type "FindMe" and returning a pointer to it
// if found in the vector or nullptr otherwise.
template<typename FindMe>
FindMe* FindFirst( std::vector<A>& vars )
{
for( auto& element : vars )
{
if( auto* result = std::get_if<FindMe>( &element.var ); result != nullptr )
return result;
}
return nullptr;
}
You could also do something like:
Code: Select all
template<typename T>
std::vector<T*> CollectAllOf( std::vector<A>& vec )
{
std::vector<T*> result;
for( auto& element : vec )
{
if( auto* result = std::get_if<T>( &element.var ); result != nullptr )
result.push_back( result );
}
return result;
}
This would collect all pointers of a specified type. If you wanted all B1 objects for instance.
Also note that in this case here, I have made it so that A is the public interface just like your polymorhpic A, but if you notice the std::vector<A> is not std::vector<A*>. This is because the compiler handles things behind the scenes to keep track of what each std::variant is actually storing. One of the reasons I find this pretty cool is how you can use it as to make a homogeneous vector or list of objects. Instead of dynamically allocating each subclass, each subclass is allocated on the stack or in the vector heap whereas a vector of polymorphic A* would have you allocate each sub-class somewhere on the heap and only storing the address in the vector.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com
-
binbinhfr
- Posts: 78
- Joined: May 9th, 2019, 10:57 pm
Post
by binbinhfr » March 30th, 2020, 9:21 pm
man, the real shame is that I was not aware about this variant type !!!!
now, believe me that i'll give it a try !
-
albinopapa
- Posts: 4373
- Joined: February 28th, 2013, 3:23 am
- Location: Oklahoma, United States
Post
by albinopapa » March 31st, 2020, 4:18 am
std::variant takes some getting use to, just a heads up. I spent the better part of 6 weeks to get to the point I could use it comfortably. Not saying you'd have to take that long, but it's not as straight forward as dynamic polymorphism.
For instance, there are the global accessors: std::get<> and std::get_if<>
If you know the type, you can use std::get<> otherwise you'll throw an exception, if the type is unknown, but you have an idea or doing what I showed, then you can use std::get_if. If the template parameter is the same as the underlying type then the pointer is returned, otherwise it's nullptr.
Then there is the std::visit function. There are multiple ways of using this function to access each underlying object and their data. If you ever go down the std::variant path and want some assistance, let me know.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com