I am trying to attach bits of data, called components, to an Entity node.
However, whenever I attach a derived component type to the Entity node, it is being upcasted to the base Component type instead of staying a child. How could I prevent this so I can make use of std::type_index?
Currently, because the Component is being upcasted, std::type_index keeps making an index for Component, rather than one of the child classes. Do I have to template out the AttachComponent method? I'd rather not.
class Entity final
{
//Typedefs
typedef std::map<std::type_index, std::shared_ptr<acorn::Component> > ComponentMap;
ComponentMap m_components;
unsigned long int m_ID;
private:
public:
explicit Entity(unsigned long int id);
~Entity();
//Getters
inline unsigned long int GetID() const
{
return m_ID;
}
template<class ComponentType>
std::weak_ptr<ComponentType> GetComponent()
{
auto component_map_it = m_components.find(std::type_index(typeid(ComponentType)));
//If the component was found
if (component_map_it != m_components.end()) {
//Get the shared_ptr of the component
std::shared_ptr<acorn::Component> base_ptr = component_map_it->second;
//Cast it to the desired component type
std::shared_ptr<ComponentType> converted_ptr(std::static_pointer_cast<ComponentType>(base_ptr));
//Convert to a weak pointer
std::weak_ptr<ComponentType> return_ptr(converted_ptr);
//Return the weak pointer
return return_ptr;
}
else {
//If no component type was found, return a nullptr.
return std::weak_ptr<ComponentType>();
}
}
//Setters
inline void AttachComponent(std::shared_ptr<Component> component)
{
auto raw_ptr = component.get();
auto insert_pair = std::make_pair(std::type_index(typeid(raw_ptr)), component);
m_components.insert(insert_pair);
}
};`
Yes, you have to make AttachComponent a template. That's the only way to preserve the type information:
template <class T>
void AttachComponent(std::shared_ptr<T> component)
{
// as before
}
Related
Historically, I've been using trait classes to hold information and apply that into a "generic" function that runs the same "algorithm." Only differed by the trait class. For example: https://onlinegdb.com/ryUo7WRmN
enum selector { SELECTOR1, SELECTOR2, SELECTOR3, };
// declaration
template < selector T> struct example_trait;
template<> struct example_trait<SELECTOR1> {
static constexpr size_t member_var = 3;
static size_t do_something() { return 0; }
};
template<> struct example_trait<SELECTOR2> {
static constexpr size_t member_var = 5;
static size_t do_something() { return 0; }
};
// pretend this is doing something useful but common
template < selector T, typename TT = example_trait<T> >
void function() {
std::cout << TT::member_var << std::endl;
std::cout << TT::do_something() << std::endl;
}
int main()
{
function<SELECTOR1>();
function<SELECTOR2>();
return 0;
}
I'm not sure how to create "generic" algorithms this when dealing with polymorphic classes.
For example: https://onlinegdb.com/S1hFLGC7V
Below I have created an inherited class hierarchy. In this example I have a base catch-all example that defaults all the parameters to something (0 in this case). And then each derived class sets overrides specific methods.
#include <iostream>
#include <memory>
#include <type_traits>
#include <assert.h>
using namespace std;
struct Base {
virtual int get_thing_one() {
return 0;
}
virtual int get_thing_two() {
return 0;
}
virtual int get_thing_three() {
return 0;
}
virtual int get_thing_four() {
return 0;
}
};
struct A : public Base {
virtual int get_thing_one() override {
return 1;
}
virtual int get_thing_three() override {
return 3;
}
};
struct B : public Base {
virtual int get_thing_one() override {
return 2;
}
virtual int get_thing_four() override{
return 4;
}
};
Here I created a simple factory, not elegant but for illustrative purposes
// example simple factory
std::shared_ptr<Base> get_class(const int input) {
switch(input)
{
case 0:
return std::shared_ptr<Base>(std::make_shared<A>());
break;
case 1:
return std::shared_ptr<Base>(std::make_shared<B>());
break;
default:
assert(false);
break;
}
}
So this is the class of interest. It is a class does "something" with the data from the classes above. The methods below are a simple addition example but imagine a more complicated algorithm that is very similar for every method.
// class that uses the shared_ptr
class setter {
private:
std::shared_ptr<Base> l_ptr;
public:
setter(const std::shared_ptr<Base>& input):l_ptr(input)
{}
int get_thing_a()
{
return l_ptr->get_thing_one() + l_ptr->get_thing_two();
}
int get_thing_b()
{
return l_ptr->get_thing_three() + l_ptr->get_thing_four();
}
};
int main()
{
constexpr int select = 0;
std::shared_ptr<Base> example = get_class(select);
setter l_setter(example);
std::cout << l_setter.get_thing_a() << std::endl;
std::cout << l_setter.get_thing_b() << std::endl;
return 0;
}
How can I make the "boilerplate" inside the setter class more generic? I can't use traits as I did in the example above because I can't tie static functions with an object. So is there a way to make the boilerplate example more common?
Somewhere along the lines of having a selector, say
enum thing_select { THINGA, THINGB, };
template < thing_select T >
struct thing_traits;
template <>
struct thing_traits<THINGA>
{
static int first_function() --> somehow tied to shared_ptr<Base> 'thing_one' method
static int second_function() --> somehow tied to shared_ptr<Base> 'thing_two' method
}
template <>
struct thing_traits<THINGB>
{
static int first_function() --> somehow tied to shared_ptr<Base> 'thing_three' method
static int second_function() --> somehow tied to shared_ptr<Base> 'thing_four' method
}
// generic function I'd like to create
template < thing_select T, typename TT = thing_traits<T> >
int perform_action(...)
{
return TT::first_function(..) + TT::second_function(..);
}
I ideally would like to modify the class above to something along the lines of
// Inside setter class further above
int get_thing_a()
{
return perform_action<THINGA>(...);
}
int get_thing_b()
{
return perform_action<THINGB>(...);
}
The answer is, maybe I can't, and I need to pass int the shared_ptr as a parameter and call the specific methods I need instead of trying to tie a shared_ptr method to a static function (in hindsight, that doesn't sound like a good idea...but I wanted to bounce my idea)
Whoever makes the actual call will need a reference of the object, one way or the other. Therefore, assuming you want perform_action to perform the actual call, you will have to pass the parameter.
Now, if you really want to store which function of Base to call as a static in thing_traits without passing a parameter, you can leverage pointer to member functions:
template <>
struct thing_traits<THINGA>
{
static constexpr int (Base::*first_function)() = &Base::get_thing_one;
...
}
template < thing_select T, typename TT = thing_traits<T>>
int perform_action(Base & b)
{
return (b.*TT::first_function)() + ...;
}
You can also play instead with returning a function object that does the call for you (and the inner function takes the parameter).
It all depends on who you need to make the call and what information/dependencies you assume you have available in each class/template.
Hi I am trying to create an object of type T where T is a pointer via the use of T result = T(). But instead of calling the constructor it simply returns a null pointer.
Here is an example of some affected code:
template <class T>
T readBlockchain(std::ifstream* stream) {
T result = T(); // Result is null after this
decltype(result->getLastBlock()) blkPtr = result->getLastBlock();
auto blk = *blkPtr;
decltype(result->getLastBlock()) lastBlock = &readBlock<decltype(blk)>(stream);
if(!lastBlock->verify())
return nullptr;
unsigned long count = *readUnsignedLong(stream);
unsigned long orphanCount = *readUnsignedLong(stream);
std::map<std::string, decltype(blk)> blocks = std::map<std::string, decltype(blk)>();
for(int i = 0; i < count - 1; i++){
decltype(blk) block = readBlock<decltype(blk)>(stream);
if(!block.verify())
return nullptr;
blocks.insert(std::make_pair(block.getHash(), block));
}
std::vector<Blockchain<decltype(blk)>*> orphanedChains = std::vector<Blockchain<decltype(blk)>*>();
for(int i = 0; i < orphanCount - 1; i++){
Blockchain<decltype(blk)>* orphan = &readOrphanedChain<Blockchain<decltype(blk)>>(stream);
orphanedChains.push_back(orphan);
}
result->setLastBlock(lastBlock);
result->setCount(count);
result->setOrphanCount(orphanCount);
result->setBlocks(blocks);
result->setOrphanedChains(orphanedChains);
return result;
}
If my understanding is correct. In order to generalize your readBlockchain correctly, you would want when T is a pointer to create a new object of T in the heap and when T is a concrete type to create a regular T object by calling the constructor of T. One solution would be to use the following specialization construct.
template<typename T>
struct CreateNew {
template<typename... Args>
static T apply(Args&&... args) { return T(std::forward<Args>(args)...); }
};
template<typename T>
struct CreateNew<T*> {
template<typename... Args>
static decltype(auto) apply(Args&&... args) { return std::make_unique<T>(std::forward<Args>(args)...); }
};
That is, you could create a template class that takes a template argument T along with a specialization of that template class for pointers of type T*. Inside the primary template (e.g., static member function apply) you'll create objects of type T by calling the constructor of class T and inside the specialization you'll create heap objects of T* (Notice that in the specialization I return a std::unique_ptr<T*> for convenience).
Thus, your readBlockChain template function would become:
template <class T>
decltype(auto) readBlockchain(std::ifstream* stream) {
auto result = CreateNew<T>::apply(/* T constructor arguments */);
...
return result;
}
Live Demo
First of all, there's no such built in concept as "interface". By interface in C++, I really mean some abstract base class that looks like:
struct ITreeNode
{
... // some pure virtual functions
};
Then we can have concrete structs that implement the interface, such as:
struct BinaryTreeNode : public ITreeNode
{
BinaryTreeNode* LeftChild;
BinaryTreeNode* RightChild;
// plus the overriden functions
};
It makes good sense: ITreeNode is an interface; not every implementation has Left & Right children - only BinaryTreeNode does.
To make things widely reusable, I want to write a template. So the ITreeNode needs to be ITreeNode<T>, and BinaryTreeNode needs to be BinaryTreeNode<T>, like this:
template<typename T>
struct BinaryTreeNode : public ITreeNode<T>
{
};
To make things even better, let's use unique pointer(smart point is more common, but I know the solution - dynamic_pointer_cast).
template<typename T>
struct BinaryTreeNode : public ITreeNode<T>
{
typedef std::shared_ptr<BinaryTreeNode<T>> SharedPtr;
typedef std::unique_ptr<BinaryTreeNode<T>> UniquePtr;
// ... other stuff
};
Likewise,
template<typename T>
struct ITreeNode
{
typedef std::shared_ptr<ITreeNode<T>> SharedPtr;
typedef std::unique_ptr<ITreeNode<T>> UniquePtr;
};
It's all good, until this point:
Let's assume now we need to write a class BinaryTree.
There's a function insert that takes a value T and insert it into the root node using some algorithm(naturally it will be recursive).
In order to make the function testable, mockable and follow good practice, the arguments need to be interface, rather than concrete classes. (Let's say this is a rigid rule that cannot be broken.)
template<typename T>
void BinaryTree<T>::Insert(const T& value, typename ITreeNode<T>::UniquePtr& ptr)
{
Insert(value, ptr->Left); // Boooooom, exploded
// ...
}
Here's the problem:
Left is not a field of ITreeNode! And worst of all, you cannot cast a unique_ptr<Base> to unique_ptr<Derived>!
What's the best practice for a scenario like this?
Thanks a lot!
Ok, over-engineering it is! But note that, for the most part, such low level data structures benefit HUGELY from transparency and simple memory layouts. Placing the level of abstraction above the container can give significant performance boosts.
template<class T>
struct ITreeNode {
virtual void insert( T const & ) = 0;
virtual void insert( T && ) = 0;
virtual T const* get() const = 0;
virtual T * get() = 0;
// etc
virtual ~ITreeNode() {}
};
template<class T>
struct IBinaryTreeNode : ITreeNode<T> {
virtual IBinaryTreeNode<T> const* left() const = 0;
virtual IBinaryTreeNode<T> const* right() const = 0;
virtual std::unique_ptr<IBinaryTreeNode<T>>& left() = 0;
virtual std::unique_ptr<IBinaryTreeNode<T>>& right() = 0;
virtual void replace(T const &) = 0;
virtual void replace(T &&) = 0;
};
template<class T>
struct BinaryTreeNode : IBinaryTreeNode<T> {
// can be replaced to mock child creation:
std::function<std::unique_ptr<IBinaryTreeNode<T>>()> factory
= {[]{return std::make_unique<BinaryTreeNode<T>>();} };
// left and right kids:
std::unique_ptr<IBinaryTreeNode<T>> pleft;
std::unique_ptr<IBinaryTreeNode<T>> pright;
// data. I'm allowing it to be empty:
std::unique_ptr<T> data;
template<class U>
void insert_helper( U&& t ) {
if (!get()) {
replace(std::forward<U>(t));
} else if (t < *get()) {
if (!left()) left() = factory();
assert(left());
left()->insert(std::forward<U>(t));
} else {
if (!right()) right() = factory();
assert(right());
right()->insert(std::forward<U>(t));
}
}
// not final methods, allowing for balancing:
virtual void insert( T const&t ) override { // NOT final
return insert_helper(t);
}
virtual void insert( T &&t ) override { // NOT final
return insert_helper(std::move(t));
}
// can be empty, so returns pointers not references:
T const* get() const override final {
return data.get();
}
T * get() override final {
return data.get();
}
// short, could probably skip:
template<class U>
void replace_helper( U&& t ) {
data = std::make_unique<T>(std::forward<U>(t));
}
// only left as customization points if you want.
// could do this directly:
virtual void replace(T const & t) override final {
replace_helper(t);
}
virtual void replace(T && t) override final {
replace_helper(std::move(t));
}
// Returns pointers, because no business how we store it in a const
// object:
virtual IBinaryTreeNode<T> const* left() const final override {
return pleft.get();
}
virtual IBinaryTreeNode<T> const* right() const final override {
return pright.get();
}
// returns references to storage, because can be replaced:
// (could implement as getter/setter, but IBinaryTreeNode<T> is
// "almost" an implementation class, some leaking is ok)
virtual std::unique_ptr<IBinaryTreeNode<T>>& left() final override {
return pleft;
}
virtual std::unique_ptr<IBinaryTreeNode<T>>& right() final override {
return pright;
}
};
Consider the following parent/child object model. The intention is for both the parent and the child to use shared_ptr to manage their lifetimes. The parent should keep a shared_ptr to (retain) its children, and the children will keep a weak_ptr to the parent.
Given that the intention is for these objects to always be managed by std::shared_ptr what is the best way to construct them? The method I've come up with (so far) feels a little clunky: I'm using factory (friend) functions and a private constructor to reduce the likelihood that raw pointers to these objects "escape". Then, the child creates a shared_ptr with this in the ctor, and puts that into the parent's vector of children. When the ctor returns the raw pointer to the factory function, the factory function uses shared_from_this() to get a shared_ptr that is "hooked up to" (i.e. sharing a reference count with) the shared_ptr that's in the parent's vector of children.
Here's what I've come up with so far:
class Child; // Forward decl
class Parent : std::enable_shared_from_this<Parent> {
public:
int value() const { return _value; };
void set_value(int newValue) { _value = newValue; };
std::vector<std::shared_ptr<const Child>> children() const {
// propagate const-ness to the child pointers we hand back.
return std::vector<std::shared_ptr<const Child>>(begin(_children), end(_children));
};
std::vector<std::shared_ptr<Child>> children() {
return _children;
};
private:
Parent(int value) : _value(value) {};
friend class Child; // So it can add itself to the _children vector
friend class std::shared_ptr<Parent>; // So that I don't have to inherit public from enable_shared_from_this
friend std::shared_ptr<Parent> CreateParent(int value); // So it can call the private ctor
std::vector<std::shared_ptr<Child>> _children;
int _value;
};
class Child : std::enable_shared_from_this<Child>
{
public:
int value() const { return _value; };
void set_value(int newValue) { _value = newValue; };
private:
Child(const std::shared_ptr<Parent>& parent, int value) : _parent(parent), _value(value) {
std::shared_ptr<Child> sp(this); // This feels wrong, but the existence of the shared_ptr in the parent's vector of children ensures that the precondition for calling shared_from_this() is met
parent->_children.push_back(sp);
};
friend std::shared_ptr<Child> CreateChild(const std::shared_ptr<Parent>& parent, int value); // So it cal call the private ctor
friend class std::shared_ptr<Child>; // So that I don't have to inherit public from enable_shared_from_this
std::weak_ptr<Parent> _parent;
int _value;
};
std::shared_ptr<Parent> CreateParent(int value) {
return std::shared_ptr<Parent>(new Parent(value));
};
std::shared_ptr<Child> CreateChild(const std::shared_ptr<Parent>& parent, int value) {
std::shared_ptr<Child> rv = (new Child(parent, value))->shared_from_this();
return rv;
};
This seems to work, but man, does it feel clunky. Is there a better way?
I'd do it this way:
class Child;
class Parent {
public:
std::vector<const Child*> children() const {
// propagate const-ness to the child pointers we hand back.
// ...
}
const std::vector<std::unique_ptr<Child>>& children() {
return _children;
}
std::shared_ptr<Parent> create() {
// I'd rather use std::make_shared() here but it needs public ctor
return std::shared_ptr<Parent>(new Parent());
}
std::unique_ptr<Child>& createChild() {
_children.emplace_back(new Child(this));
return _children.back();
}
private:
Parent();
std::vector<std::unique_ptr<Child>> _children;
};
class Child
{
private:
Child(Parent* parent) : _parent(parent) {}
friend class Parent;
Parent* _parent;
};
I stripped out the "value" boilerplate for clarity. I also tried to use the minimal sophistication level of smart pointers that seemed viable to get the job done. I may not have gotten it 100% perfect for your specific use case, but you should think about more clearly defined lifetime/ownership semantics. Having everything sharing everything is sort of a mess and leads to lack of clarity...having clear ownership can make things simpler. And since the Parent class still manages the lifetime of each Child, there's no need to have a fancy pointer from Child back to Parent--a raw pointer will work because the Child won't outlive the Parent.
Given your description of the uncomfortable split of the parent/children management, you can simplify as follows,
class Child;
class Parent {
private:
Parent() {};
friend std::shared_ptr<Child> CreateChild(const std::shared_ptr<Parent>& parent);
std::vector<std::shared_ptr<Child>> _children;
};
class Child {
private:
Child(const std::shared_ptr<Parent>& parent) : _parent(parent) {};
friend std::shared_ptr<Child> CreateChild(const std::shared_ptr<Parent>& parent);
std::weak_ptr<Parent> _parent;
};
std::shared_ptr<Child> CreateChild(const std::shared_ptr<Parent>& parent) {
auto child = std::shared_ptr<Child>(new Child(parent));
parent->_children.push_back(child);
return child;
}
Also notice that there is no shared_from_this here, maybe it is necessary for your other purposes, but it isn't necessary to manage the parent-child relationship.
I'm building a large project on Debian 6.0.6 (with gcc 4.4.5) that was initially built in Microsoft VS (2008, I think).
What seems to be the problem is that when I declare a member as
typedef typename std::set<T>::iterator iterator, and then later use this iterator, gcc appears to interpret this as (const T*).
The part of the class containing the typename designation:
template <class entityType>
class entityArray
{
private: std::set<entityType> m_array;
public: typedef typename std::set<entityType>::iterator iterator;
...
public:
entityType* At( const char* name);
...
};
plus a few other classes that are needed for the discussion:
class entity
{
private:
entity* m_parent;
int m_ncid;
std::string m_name;
public:
entity () { m_ncid = 0; m_parent = NULL;}
virtual ~entity () {};
...
};
class attribute : public entity
{
public:
attribute(){};
virtual ~attribute(){};
};
class var : public entity
{
private:
entityArray<attribute> m_atts;
public:
var(){}
virtual ~var(){}
...
};
class dim : public entity
{
public:
dim() {};
virtual ~dim() {};
};
class group : public entity
{
private:
entityArray<var> m_vars;
entityArray<dim> m_dims;
...
public:
dim* DimAt( const char* dimname ) { return m_dims.At(dimname);}
};
Now an iterator is initialized through a call to the function DimAt which in turn calls At. The At function in the first class is defined as:
template <class entityType>
entityType* entityArray<entityType>::At( const char* name )
{
entityType dummy;
iterator iter;
entityType* ptr;
... define dummy ...
iter = m_array.find( dummy );
ptr = (iter != m_array.end()) ? &(*iter) : NULL;
return ptr;
}
Compiling the above produces
error: invalid conversion from const dim* to dim*., referring to &(*iter).
I realize that typename is required for declaring iterator, since the type is a dependent and qualified name, but I don't see why this substitution (const *) is being performed by the compiler. I would appreciate any help that you could provide. Thanks!
This has absolutely nothing to do with typename.
The standard allows std::set<T>::iterator and std::set<T>::const_iterator to be the same type, and with GCC the types are the same.
The reason is that modifying an element of a std::set e.g. by *iter = val might invalidate the ordering of the set elements, breaking the invariant that the elements of the set are always in order. By making the iterator type a constant iterator instead of a mutable iterator it's not possible to alter the element, preventing you from corrupting the set's ordering.
So with GCC's implementation, when you dereference the iterator using *iter you get a const entitType& and when you take its address using &*iter you get a const entityType*