I observed that in my program I needed to make several classes use the following common pattern. The idea behind it is that resource_mgr maintains a list of reference-counted pointers to resource objects, and exclusively controls their lifetime. Clients may not create or delete resource instances, but may request them from resource_mgr.
class resource_impl
{
public:
// ...
private:
resource_impl(...);
~resource_impl();
// ...
friend class resource_mgr;
}
class resource_mgr
{
public:
// ...
shared_ptr<resource_impl> new_resource(...);
private:
std::vector<shared_ptr<resource_impl> > resources_;
static void delete_resource(resource* p); // for shared_ptr
}
How can I (or can I?) define a template to capture this common behavior?
The following illustrates how this template might be used:
class texture_data
{
// texture-specific stuff
}
typedef resource_impl<texture_data> texture_impl;
// this makes texture_impl have private *tors and friend resource_mgr<texture_impl>
typedef resource_mgr<texture_impl> texture_mgr;
//...
texture_mgr tmgr;
shared_ptr<texture_impl> texture = tmgr.new_resource(...);
Update: Various instantiations of resource_impl should all have in common the following properties:
They have private constructors and destructor
Their "associated" resource_mgr (the manager class that manages the same type of resource) is a friend class (so it can create/destroy instances)
First add the interface :
class resource_interface
{
public:
virtual ~resource_interface() = 0;
virtual void foo() = 0;
};
Then change the resource_impl into template :
template< typename T >
class resource_impl : public T
{
public:
// ...
private:
resource_impl(...);
~resource_impl();
// ...
friend template< typename > class resource_mgr;
}
Then change resource_mgr into template:
template< typename T >
class resource_mgr
{
public:
// ...
shared_ptr<T> new_resource(...);
private:
std::vector<shared_ptr<T> > resources_;
static void delete_resource(T* p); // for shared_ptr
}
And you should have very generic resource_impl and resource_mgr classes.
Related
I am writing an arbitrary-ranked tensor (multidimensional array) class in C++ and would like to have static and dynamic memory versions of it. However, I am struggling to think of a way to avoid having to duplicate methods in the static/dynamic versions of the class, considering that the underlying data containers would be different. I hope the following minimal example illustrates my point:
// Product function
template <typename ...data_type>
constexpr auto Product(data_type ..._values)
{
return (_values * ...);
}
// Static memory version
template <class t_data_type, unsigned ...t_dimensions>
class StaticTensor
{
private:
std::array<t_data_type, Product(t_dimensions...)> Entries; // Store entries as contiguous memory
public:
StaticTensor() = default;
~StaticTensor() = default;
void StaticMethod()
{
// Some code that operates on Entries.
}
};
// Dynamic memory version
template <class t_data_type>
class DynamicTensor
{
private:
std::vector<t_data_type> Entries;
public:
DynamicTensor() = default;
~DynamicTensor() = default;
template <typename ...t_dimensions>
void Resize(t_dimensions ...dims)
{
Entries.resize(Product(dims...));
}
void DynamicMethod()
{
// Some code that operates on Entries.
}
};
I have considered inheritance-based/polymorphic approaches, but it seems that I'd still have to implement separate methods in each of the specialised classes. I would ideally like all the methods to operate on the underlying iterators in std::array and std::vector, without having to worry about which data container they belong to. Can anyone suggest how I can go about doing this?
You can use CRTP techniques to create a TensorBase, then convert *this to Derived& to access the derived class's Entries inside Method():
template <class Derived>
class TensorBase
{
public:
void Method()
{
auto& Entries = static_cast<Derived&>(*this).Entries;
// Some code that operates on Entries.
}
};
Then your StaticTensor/DynamicTensor can inherit TensorBase to obtain the Method(). In order to enable the base class to access private members, you also need to set the base class as a friend:
// Static memory version
template <class t_data_type, unsigned ...t_dimensions>
class StaticTensor
: public TensorBase<StaticTensor<t_data_type, t_dimensions...>>
{
using Base = TensorBase<StaticTensor<t_data_type, t_dimensions...>>;
friend Base;
private:
std::array<t_data_type, Product(t_dimensions...)> Entries;
public:
StaticTensor() = default;
~StaticTensor() = default;
};
// Dynamic memory version
template <class t_data_type>
class DynamicTensor
: public TensorBase<DynamicTensor<t_data_type>>
{
using Base = TensorBase<DynamicTensor<t_data_type>>;
friend Base;
private:
std::vector<t_data_type> Entries;
public:
DynamicTensor() = default;
~DynamicTensor() = default;
};
Demo.
I want to design a component-based weapon template for my game. However, it seems no way to add/remove a class member or create a code?
Sorry for my expression and lack of terminology, for I am not graduated from dept. of computer science or software engineer, I know little of what those stuff called by professionals.
Here is the component code looks like:
class CBaseWpnCmpt : public std::enable_shared_from_this<CBaseWpnCmpt>
{
public:
typedef std::shared_ptr<CBaseWpnCmpt> PTR;
private:
CBaseWpnCmpt() = default;
public:
CBaseWpnCmpt(const CBaseWpnCmpt& s) = default;
CBaseWpnCmpt(CBaseWpnCmpt&& s) = default;
CBaseWpnCmpt& operator=(const CBaseWpnCmpt& s) = default;
CBaseWpnCmpt& operator=(CBaseWpnCmpt&& s) = default;
virtual ~CBaseWpnCmpt() {}
protected:
CBaseWeaponInterface::PTR m_pWeapon { nullptr };
public:
template <class CComponent>
static std::shared_ptr<CComponent> Create(CBaseWeaponInterface::PTR pWeapon)
{
std::shared_ptr<CComponent> pComponent = std::make_shared<CComponent>();
pComponent->m_pWeapon = pWeapon;
return pComponent;
}
};
And this is what a weapon body code looks like: (And the problem occurs)
template < class CWeapon,
class ...CComponents
>
class CBaseWeaponTemplate : public CBaseWeaponInterface
{
public:
std::list<CBaseWpnCmpt::PTR> m_lstComponents;
public:
virtual void SecondaryAttack(void) // Example method.
{
for (auto& pComponent : m_rgpComponents)
{
pComponent->SecondaryAttack();
}
}
};
How am I suppose to create all these argument packs as member of the template? Currently I tried to enlist them into a pointer std::list container, but I just can't figure out how to achieve it at all.
In other words, how can I make a template when I fill in blank likt this:
class CAK47 : public CBaseWeaponTemplate<CAK47, CLongMagazine, CWoodenStock>
will generate this:
class CAK47
{
CLongMagazine m_comp1;
CWoodenStock m_comp2;
//... other stuff
};
Or alternatively, generate this:
class CAK47
{
CAK47() // constructor
{
for (/* somehow iterate through all typenames */)
{
CBaseWpnCmpt::PTR p = std::make_shared<typename>();
m_lstComponents.emplace_back(p);
}
}
};
One way of doing so from C++11 on-wards would be to store the template types used for this particular weapon inside an std::tuple
template <typename Weapon, typename... Attachments>
class WeaponWithAttachments {
protected:
WeaponWithAttachments() {
return;
}
std::tuple<Attachments...> attachment_types;
};
and then using that tuple to initialise a vector of shared pointers with a protected constructor taking a tuple to access the template types again.
class SomeWeaponWithAttachments: public WeaponWithAttachments<SomeWeapon,SomeAttachment,AnotherAttachment> {
public:
SomeWeaponWithAttachments()
: SomeWeaponWithAttachments{attachment_types} {
return;
}
protected:
template <typename... Attachments>
SomeWeaponWithAttachments(std::tuple<Attachments...> const&)
: attachments{std::make_shared<Attachments>()...} {
return;
}
std::vector<std::shared_ptr<BaseAttachment>> attachments;
};
Try it here!
If the attachments vector is already declared inside the parent class like it seems to be the case for you might also avoid the tuple and the protected constructor with initialising the attachments already inside the parent class
template <typename Weapon, typename... Attachments>
class WeaponWithAttachments {
protected:
WeaponWithAttachments()
: attachments{std::make_shared<Attachments>()...} {
return;
}
std::vector<std::shared_ptr<BaseAttachment>> attachments;
};
and then only calling the constructor of the base class in the derived class
class SomeWeaponWithAttachments: public WeaponWithAttachments<SomeWeapon,SomeAttachment,AnotherAttachment> {
public:
SomeWeaponWithAttachments()
: WeaponWithAttachments<SomeWeapon,SomeAttachment,AnotherAttachment>() {
return;
}
};
Try it here!
If that is no option for you, then you can use the tuple to iterate over all the template arguments using C++17 fold expressions:
class SomeWeaponWithAttachments: public WeaponWithAttachments<SomeWeapon,SomeAttachment,AnotherAttachment> {
public:
SomeWeaponWithAttachments()
: SomeWeaponWithAttachments{attachment_types} {
return;
}
protected:
template <typename... Attachments>
SomeWeaponWithAttachments(std::tuple<Attachments...> const&) {
(attachments.push_back(std::make_shared<Attachments>()), ...);
return;
}
};
Try it here!
In C++17 you might also add a static assertion with fold expressions into the constructor to make sure that the types actually inherit from BaseAttachment:
static_assert((std::is_base_of_v<BaseAttachment, Attachments> && ...), "Template arguments must inherit from 'BaseAttachment'.");
I was looking into Alexandrescu's singleton created with policies, which is an interesting design. (http://loki-lib.sourceforge.net/html/a00670.html)
However, he first explains that you should guarantee a Singleton's uniqueness, which I agree with. But when you look at the policy implementation, he has a policy CreateWithNew which invokes the new operator on the argument provided with T. which means the constructor has to be public, meaning any user creating the singletonHolder can also instantiate that class directly himself.
Obviously it is still a nice design, but I just wanted to make sure if I missed something important or if he sacrificed the uniqueness for a versatile design.
Thanks!
A test example:
The following class has a TestObject which is the Singleton class, and a simple createViaNewPolicy which just uses new to allocate the singleton. notice that the constructor of TestObject has to be public in order for this to work.
//////////////////////////////////////////////////////////////////////////
class TestObject
{
public: // change this to private (to guarantee uniqueness) but then it wont compile
TestObject() {}
int foo() {return 1;}
~TestObject() {}
};
//////////////////////////////////////////////////////////////////////////
template< class T, template <class> class CreationPolicy >
class SingletonHolder
{
public:
T* SingletonHolder<T, CreationPolicy>::Instance()
{
if (!pInstance_)
{
pInstance_ = CreationPolicy<T>::Create();
}
return pInstance_;
}
private:
static T* pInstance_;
};
template< class T, template <class> class CreationPolicy >
T* SingletonHolder<T, CreationPolicy>::pInstance_;
//////////////////////////////////////////////////////////////////////////
template<class T>
class CreateViaNew
{
public:
static T* Create()
{
return new T();
};
};
//////////////////////////////////////////////////////////////////////////
int _tmain(int argc, _TCHAR* argv[])
{
SingletonHolder<TestObject, CreateViaNew> mySingletonHolder;
TestObject* testObj = mySingletonHolder.Instance();
return 0;
}
CreateUsingNew is just the policy. They way it's used is as a template template parameter inside the Singleton class. So the singleton class will have the following layout (exctract from modern C++ design) :
class Singleton
{
Singleton& Instance();
... operations...
public:
Singleton();
Singleton(Singleton const&);
Singleton& operator=(Singleton const&);
~Singleton();
}
There the creation of the object can only be done through the Instance method. In turn that method reads (extract from the link to Loki) :
template
<
class T,
template <class> class CreationPolicy,
... some other arguments...
>
void SingletonHolder<T, CreationPolicy,
...some other arguments...>::MakeInstance()
{
... stuff ...
if (!pInstance_)
{
if (destroyed_)
{ /* more stuff */ }
pInstance_ = CreationPolicy<T>::Create();
/* even more stuff */
}
}
So the line where the magic happens is pInstance = CreationPolicy<T>::Create();
Itself, every construction method for a Singleton object is private and underlying implementation of the construction policy can only be accessed through the public MakeInstance method
I have quite a lot of classes declared, all of them are inheriting from a base (kind of abstract) class ... so all of them have common methods I'd like to use ...
now, I need to have a list of classes (not objects), later make instance of them in a loop and use the instances for calling mentioned common methods ...
the pseudo-code
class Abstract {
void Something();
}
class TaskOne : public Abstract {
void Something(); // method implemented somewhere below
}
class TaskTwo : public Abstract {
void Something(); // method implemented somewhere below
}
...
list<Abstract> lst;
lst.push_back(TaskOne); // passing class type, not instance!
lst.push_back(TaskTwo);
Abstract tmpObject = new lst[0]; //I know its wrong, just a way of expressing what I'd like to do to have instance of TaskOne!
please give any tips ...
You could create a templated factory object:
struct IFactory { virtual IBaseType* create() = 0; };
template< typename Type > struct Factory : public IFactory {
virtual Type* create( ) {
return new Type( );
}
};
struct IBaseType { /* common methods */ virtual ~IBaseType(){} };
IFactory* factories[] = {
new Factory<SubType1>
, new Factory<SubType2>
// ...
};
std::vector<IBaseType*> objects;
objects.push_back( factories[1]->create() ); // and another object!
// don't forget to delete the entries in the
// vector before clearing it (leak leak)
I would go with the templated factory, like xtofl proposed, but simplify its usage
struct IFactory { virtual IBaseType* create() = 0; };
template< typename Type > struct Factory : public IFactory {
virtual Type* create( ) {
return new Type( );
}
};
list<IFactory*> lst;
lst.push_back(new Factory<TaskOne>);
lst.push_back(new Factory<TaskTwo>);
Abstract *tmpObject = lst[0]->create();
// don't forget to delete all the factory instances!
Boost.MPL is the answer here. Don't listen to Hassan Syed.
Example:
namespace mpl=boost::mpl;
typedef mpl::vector< CLASS1, CLASS2,...,CLASSN > class_list_a;
typedef mpl::push_back< class_list_a ANOTHER_CLASS>::type class_list_b;
typedef mpl::push_back<
typename mpl::push_back<
class_list_b,
ANOTHER_TYPE_1>::type,
ANOTHER_TYPE_2>::type
class_list;
struct functor {
template<class U> void operator(U& u) {
u.something();
}
};
...
// in some function
boost::mpl::for_each<class_list>( functor() );
EDIT: BOOST_PP could also work
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#define MY_CLASSES (TYPE_1)(TYPE_2)(TYPE_N)
#define MY_FUNCTION(r, data, elem) elem() . data;
#define CALL_SOMETHING_ON(_CLASSES_, _ARGS_) \
BOOST_PP_SEQ_FOR_EACH( MY_FUNCTION, someThing( _ARGS_ ), _CLASSES_ )
int foo = 1;
CALL_SOMETHING_ON( MY_CLASSES, foo )
running cpp foo.c yields:
int foo = 1;
TYPE_1() . someThing( foo ); \
TYPE_2() . someThing( foo ); \
TYPE_N() . someThing( foo );
I'd suggest using a factory-based design. Your list stores a bunch of factory instances, and you can create an Abstract-derived instance by calling the right factory method.
For example:
class Abstract
{
virtual void Something() = 0;
};
class TaskOne : public Abstract
{
void Something();
};
class AbstractFactory
{
public:
Abstract* CreateInstance();
};
template <class T> class Factory : public AbstractFactory
{
public:
Abstract* CreateInstance()
{
return new T();
}
};
...
std::vector<AbstractFactory*> Factories;
Factories.push_back(new Factory<TaskOne>());
...
Abstract *Instance = Factories[ 0 ]->CreateInstance();
Factory pattern could work (see e.g. http://en.wikipedia.org/wiki/Factory_method_pattern). Something along the lines of:
#define stringify(a) #a
static int hashstr(const char* s) {/*hash fn of choice*/}
list<int> types;
lst.push_back(hashtr(stringify(TaskOne))); // passing class type, not instance!
lst.push_back(hashtr(stringify(TaskTwo)));
static Abstract* Instance(int classid)
{
switch(id)
{
case hashstr(stringify(TaskOne)):
return new TaskOne;
//etc
}
}
You can be considerably more elegant with extra work. Embedding class id's into the class declaration as static ints is often a good start.
You need to have have a list of pointers of type abstract. initialize all the pointers to null and construct to the correct class later. You don't need to pre-type the pointers before hand. You can just rely on the RTTI latter.
If you do need to pre-type them before hand than just add an enum to Abstract for the types. This saves you memory if the inherited classes are large. But you have to maintain the enum of types yourself, not the most elegant way of doing things.
If you have to initialize and pre-type them, just initialize the classes using the default constructor. But this way you are using memory when not needed. RTTI will be your friend here in this case.
I cannot figure this out. I need to have an abstract template base class, which
is the following:
template <class T> class Dendrite
{
public:
Dendrite()
{
}
virtual ~Dendrite()
{
}
virtual void Get(std::vector<T> &o) = 0;
protected:
std::vector<T> _data;
};
Now, I derive from this which specifies exact usage of Dendrite.
Now the problem.
How do I create a vector of pointers to the base-class with no specific type, which
I want to specify by pushing elements to it later? Something like:
class Foo
{
public:
...
private:
std::vector<Dendrite *> _inputs; //!< Unfortunately, this doesn't work...
//! Now I could later on push elements to this vector like
//!
//! _inputs.push_back(new DeriveFromDendrite<double>()) and
//! _inputs.push_back(new DeriveFromDendrite<int>()).
};
Is this possible or am I missing something very basic here?
Typically this is done by your template inheriting from an interface class, IE:
template <class T> class Dendrite : public IDendrite
{
public:
Dendrite()
{
}
virtual ~Dendrite()
{
}
void Get(std::vector<T> &o) = 0;
protected:
std::vector<T> _data;
};
and then you're IDendrite class could be stored as pointers:
std::vector<IDendrite*> m_dendriteVec;
However, in your situation, you are taking the template parameter as part of your interface. You may also need to wrap this also.
class IVectorParam
{
}
template <class T>
class CVectorParam : public IVectorParam
{
std::vector<T> m_vect;
}
giving you
class IDendrite
{
...
public:
virtual ~IDendrite()
virtual void Get(IVectorParam*) = 0;
}
template <class T> class Dendrite : public IDendrite
{
...
// my get has to downcast to o CVectorParam<T>
virtual void Get(IVectorParam*);
};
Yes it is possible. Just make sure to provide virtual functions, and virtual destructor. In addition, you can use typeid to get the actual type (as well as dynamic_cast to check the type)