The following is an attempt at implementing a shared pointer with a modified semantics of operator==
:
template <typename T>
struct deref_shared_ptr: private std::shared_ptr<T> {
using Base = std::shared_ptr<T>;
// ... using statements to include functionality from the base.
bool operator==(const deref_shared_ptr rhs) const {
return (**this == *rhs);
}
};
I am struggling with implementing an equivalent of std::make_shared
for this type. This is my attempt:
template< class T, class... Args >
deref_shared_ptr<T> make_deref_shared( Args&&... args ) {
return reinterpret_cast<deref_shared_ptr<T>>(std::make_shared<T>(args...));
}
This does not work: the compiler (g++ 5.4.0
) complains about an invalid cast. Why does it not work and what should I do instead of this cast?
You see this compiler error message because the reinterpret_cast
cannot make casts through the private inheritance. Please check the following themes on this topic: difference between c++ casts, conversion which may be handled by c-style cast only.
The only way to go through the private
inheritance is the c-style cast. So, changing your example as follows makes your example work:
template< class T, class... Args >
deref_shared_ptr<T> make_deref_shared(Args&&... args) {
return (deref_shared_ptr<T>)(std::make_shared<T>(args...));
}
The c-style cast is not safe in the general case since it may work incorrectly in cases of multiple inheritance and some other cases, but AFAIK it's safe in this case.
I suggest your deref_shared_ptr
to implement a constructor that receive a std::shared_ptr
as parameter, so the conversion would be possible. Right now your compiler has no idea how to make a deref_shared_ptr
from a std::shared_ptr
. This is exactly what we will teach your compiler to do.
I noticed you add a custom operator==
to compare correctly your type with a std::shared_ptr
. Here we want to do the same thing but with constructor. We want a constructor that construct correctly with your type with a std::shared_ptr
!
The constructor would look like this:
template<typename T>
struct deref_shared_ptr : private std::shared_ptr<T> {
// An alias to the parent may help msvc with templated parent types
using parent = std::shared_ptr<T>;
// Implement a constructor that takes shared_ptr by copy and move
deref_shared_ptr(const parent& ptr) : parent{ptr} {}
deref_shared_ptr(parent&& ptr) : parent{std::move(ptr)} {}
// stuff...
};
Then, the make function becomes trivial to implement:
template<typename T, typename... Args>
deref_shared_ptr<T> make_deref_shared(Args&&... args) {
// Don't forget perfect forwarding here!
return std::make_shared<T>(std::forward<Args>(args)...);
}
EDIT:
Alternatively, if your constructors are not doing any operation, you can make use of inheriting constructors:
template<typename T>
struct deref_shared_ptr : private std::shared_ptr<T> {
using parent = std::shared_ptr<T>;
// Implement constructors
using parent::parent;
// stuff...
};
That would simplify constructor implementations and will make your type compatible by construction with std::shared_ptr
.