问题
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?
回答1:
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.
回答2:
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
.
来源:https://stackoverflow.com/questions/38682050/how-to-cast-to-privately-derived-child-type