As many other C++0x users I’m trying to make a smart pointer interface for my projects. Ideally, I’d like syntax like this, hiding both types and std::make_shared<T>() calls.
Foo::Ptr foo = Foo::shared();
Foo::UPtr unique_foo = Foo::unique();
I’d like to place declarations inside a struct to inherit from:
template <class T>
struct SmartDefs
{
typedef std::shared_ptr<T> Ptr;
typedef std::unique_ptr<T> UPtr;
template <class... P>
static Ptr shared(P&&... p)
{
return std::make_shared<T>(std::forward<P>(p)...);
}
template <class... P>
static UPtr unique(P&&... p)
{
return std::unique_ptr<T>(new T(std::forward<P>(p)...));
}
};
Now this works nicely by itself, but when inheritance comes into the picture I get problems, since the typedefs and shared/unique static methods are defined twice. I managed to work around this problem using some ugly macros, private inheritance and require more typing, but I’d like to avoid this:
#include <memory>
#include <iostream>
template <class T>
struct SmartDefs
{
typedef std::shared_ptr<T> Ptr;
typedef std::unique_ptr<T> UPtr;
template <class... P>
static Ptr shared(P&&... p)
{
return std::make_shared<T>(std::forward<P>(p)...);
}
template <class... P>
static UPtr unique(P&&... p)
{
return std::unique_ptr<T>(new T(std::forward<P>(p)...));
}
};
#define DECL_SMART(type) using SmartDefs< type >::Ptr; \
using SmartDefs< type >::UPtr; \
using SmartDefs< type >::shared; \
using SmartDefs< type >::unique
class Foo : private SmartDefs<Foo>
{
public:
DECL_SMART(Foo);
virtual void foo() const { std::cout << "Foo" << std::endl; }
};
class Bar : public Foo, private SmartDefs<Bar>
{
public:
DECL_SMART(Bar);
void foo() const { std::cout << "Bar" << std::endl; }
};
template <class T>
struct Baz : private SmartDefs<Baz<T>>
{
DECL_SMART(Baz<T>);
void foo(const T& in) const { std::cout << in << std::endl; }
};
int main()
{
auto foo = Foo::shared();
auto bar = Bar::shared();
auto baz = Baz<int>::shared();
foo->foo();
bar->foo();
baz->foo(10);
foo = bar;
foo->foo();
}
I’ve tested something like this, but it still gives me ambiguous reference to shared():
template <class T>
struct SmartPtr : private SmartDefs<T>
{
using SmartDefs<T>::Ptr;
using SmartDefs<T>::UPtr;
using SmartDefs<T>::shared;
using SmartDefs<T>::unique;
};
class Foo : public SmartPtr<Foo> {};
Could you expand on:
Do you mean multiple Inheritance of two base classes each inheriting from your SmartDefs class? Do you mean Inheriting from both the SmartDefs class and a base class which itself inherits from the SmartDefs class?
Either way, your problem is not with C++0x of course, but general ambiguity of base members.
Example:
So, you need to solve the problem the same way: explicitly disambiguate at call time, or, preferably, overload the functions/typedefs in your derived class.
However, I am not sure I would recommend your solution at all. In the face of inheritance
Derived::unique()would return aunique_ptr<Base>if Derived did not inherit from your SmartPtr class. The only “safe” way to implement something like this is with a virtual Create() function (in your case: CreateUnique, CreateShared perhaps).I would personally prefer to write a global
make_sharedto wrapstd::make_sharedand write my ownmake_uniquein the same namespace.The few character difference here is trivial compared to not having to inherit every class from SmartDefs, and avoiding the big risk of improper use.
Edit: I forgot to cover that you will lose typedefs for the return type this way. You could use type_traits, but I actually consider lack of typedef a feature here. Information aboyt core classes such as std::shared_ptr and std::unique_ptr need not be typedef-ed away, and between
auto, templates, anddecltype, there is little need for explicit typedefs.