动态转换在模板成员函数内部同时使用共享指针和弱指针,无需代码重复
Dynamic casting work both shared and weak pointers inside of template member function without code duplication
我有我的 Find 方法,我想将其与共享指针和弱指针一起使用。 Live example
using namespace std;
template<typename value>
struct A
{
template < typename T, typename F >
T Find( F filterFunction)
{
for ( size_t i = 0; i < iteratableList.size(); i++)
{
auto castedTerrain = dynamic_pointer_cast<typename T::element_type>(iteratableList[i]);
if ( castedTerrain && filterFunction(castedTerrain) )
return iteratableList[i];
}
return T();
}
std::vector<value> iteratableList;
};
int main()
{
{
std::vector<std::shared_ptr<std::string>> names = { make_shared<std::string>("needle"), make_shared<std::string>("manyOtherNames") } ;
A<std::shared_ptr<std::string>> iterateable{ names };
iterateable.Find<std::shared_ptr<std::string>>([] ( std::shared_ptr<std::string> in ){ return *in == "needle";});
}
// When I use weak pointer my Find function fails.
//{
// std::vector<std::shared_ptr<std::string>> weakNames ;
// for ( auto elem : names )
// weakNames.push_back(elem)
// A<std::weak_ptr<std::string>> iterateable{ weakNames };
// iterateable.Find<std::weak_ptr<std::string>>([] ( std::weak_ptr<std::string> in ){ return *in == "needle";});
//}
}
我知道我可以做类似的事情
std::is_same< std::weak_ptr ... >
并使用 std::true_type
和 std::false_type
但我很好奇是否有更好更清晰的方法来避免仅针对 .lock()
方法的代码重复。
只要有一个模板函数就可以用来获取"real"指针。 std::shared_ptr
的特化只是 returns 参数:
template <typename T>
struct resolve_pointer;
template <typename T>
struct resolve_pointer<std::shared_ptr<T>>
{
static std::shared_ptr<T> resolve(std::shared_ptr<T> & p) const {
return p;
}
};
template <typename T>
struct resolve_pointer<std::weak_ptr<T>>
{
static std::shared_ptr<T> resolve(std::weak_ptr<T> & p) const {
return p.lock();
}
};
现在你的 Find
函数,用 resolve_pointer<T>::resolve(iteratableList[i])
.
代替 iteratableList[i]
我是个土豆,一个重载的自由函数也可以工作,而且更容易理解:
template <typename T>
std::shared_ptr<T> resolve_pointer(std::shared_ptr<T> & p) {
return p;
}
template <typename T>
std::shared_ptr<T> resolve_pointer(std::weak_ptr<T> & p) {
return p.lock();
}
如果您的目标是能够扩展您的代码以提供与任何 strong/weak 指针对的互操作性,这些指针对具有已实现的动态转换操作(此处显示 std::strong/weak_ptr 和 boost ::strong/weak_ptr),你可以使用一组特征来做到这一点,就像这样......当心,前方有龙:
// Defines a resolve static function to get a strong pointer from either
// a strong or a weak pointer.
template <typename T>
struct smart_pointer_info;
template <typename T>
struct smart_pointer_info<std::shared_ptr<T>>
{
typedef std::shared_ptr<T> ptr_type;
typedef T element_type;
typedef std::shared_ptr<T> resolved_type;
static resolved_type resolve(ptr_type & p) {
return p;
}
};
template <typename T>
struct smart_pointer_info<std::weak_ptr<T>>
{
typedef std::weak_ptr<T> ptr_type;
typedef T element_type;
typedef std::shared_ptr<T> resolved_type;
static resolved_type resolve(ptr_type & p) {
return p.lock();
}
};
template <typename T>
struct smart_pointer_info<boost::shared_ptr<T>>
{
typedef boost::shared_ptr<T> ptr_type;
typedef T element_type;
typedef boost::shared_ptr<T> resolved_type;
static resolved_type resolve(ptr_type & p) {
return p;
}
};
template <typename T>
struct smart_pointer_info<boost::weak_ptr<T>>
{
typedef boost::weak_ptr<T> ptr_type;
typedef T element_type;
typedef boost::shared_ptr<T> resolved_type;
static resolved_type resolve(ptr_type & p) {
return p.lock();
}
};
// Provides a static "cast" function that converts a strong pointer T
// into a strong point that points at an object of type D.
template <typename T, typename D>
struct smart_pointer_dynamic_cast;
template <typename T, typename D>
struct smart_pointer_dynamic_cast<std::shared_ptr<T>, D>
{
typedef std::shared_ptr<T> ptr_type;
typedef std::shared_ptr<D> cast_type;
static cast_type cast(ptr_type & p) {
return std::dynamic_pointer_cast<D>(p);
}
};
template <typename T, typename D>
struct smart_pointer_dynamic_cast<boost::shared_ptr<T>, D>
{
typedef boost::shared_ptr<T> ptr_type;
typedef boost::shared_ptr<D> cast_type;
static cast_type cast(ptr_type & p) {
return boost::dynamic_pointer_cast<D>(p);
}
};
// Helper so we can omit the template parameter for the source pointer type.
template <typename D>
struct dynamic_cast_helper
{
template <typename P>
static typename smart_pointer_dynamic_cast<typename smart_pointer_info<P>::resolved_type, D>::cast_type cast(P & p) {
typename smart_pointer_info<P>::resolved_type r = smart_pointer_info<P>::resolve(p);
return smart_pointer_dynamic_cast<typename smart_pointer_info<P>::resolved_type, D>::cast(r);
}
};
// Then we might use it like so:
class A {
public:
virtual void print() {
std::cout << "A::print()" << std::endl;
}
};
class B : public A {
public:
virtual void print() {
std::cout << "B::print()" << std::endl;
}
};
int main()
{
auto x = std::make_shared<B>();
std::weak_ptr<B> xw{x};
auto y = boost::make_shared<B>();
boost::weak_ptr<B> yw{y};
dynamic_cast_helper<A>::cast(x)->print();
dynamic_cast_helper<A>::cast(xw)->print();
dynamic_cast_helper<A>::cast(y)->print();
dynamic_cast_helper<A>::cast(yw)->print();
return 0;
}
(Demo)
你的转换 dynamic_pointer_cast<typename T::element_type>(iteratableList[i])
然后变成 dynamic_cast_helper<typename smart_pointer_info<T>::element_type>::cast(iteratableList[i])
并且沿途的所有类型都被编译器推断出来。
我有我的 Find 方法,我想将其与共享指针和弱指针一起使用。 Live example
using namespace std;
template<typename value>
struct A
{
template < typename T, typename F >
T Find( F filterFunction)
{
for ( size_t i = 0; i < iteratableList.size(); i++)
{
auto castedTerrain = dynamic_pointer_cast<typename T::element_type>(iteratableList[i]);
if ( castedTerrain && filterFunction(castedTerrain) )
return iteratableList[i];
}
return T();
}
std::vector<value> iteratableList;
};
int main()
{
{
std::vector<std::shared_ptr<std::string>> names = { make_shared<std::string>("needle"), make_shared<std::string>("manyOtherNames") } ;
A<std::shared_ptr<std::string>> iterateable{ names };
iterateable.Find<std::shared_ptr<std::string>>([] ( std::shared_ptr<std::string> in ){ return *in == "needle";});
}
// When I use weak pointer my Find function fails.
//{
// std::vector<std::shared_ptr<std::string>> weakNames ;
// for ( auto elem : names )
// weakNames.push_back(elem)
// A<std::weak_ptr<std::string>> iterateable{ weakNames };
// iterateable.Find<std::weak_ptr<std::string>>([] ( std::weak_ptr<std::string> in ){ return *in == "needle";});
//}
}
我知道我可以做类似的事情
std::is_same< std::weak_ptr ... >
并使用 std::true_type
和 std::false_type
但我很好奇是否有更好更清晰的方法来避免仅针对 .lock()
方法的代码重复。
只要有一个模板函数就可以用来获取"real"指针。 std::shared_ptr
的特化只是 returns 参数:
template <typename T>
struct resolve_pointer;
template <typename T>
struct resolve_pointer<std::shared_ptr<T>>
{
static std::shared_ptr<T> resolve(std::shared_ptr<T> & p) const {
return p;
}
};
template <typename T>
struct resolve_pointer<std::weak_ptr<T>>
{
static std::shared_ptr<T> resolve(std::weak_ptr<T> & p) const {
return p.lock();
}
};
现在你的 Find
函数,用 resolve_pointer<T>::resolve(iteratableList[i])
.
iteratableList[i]
我是个土豆,一个重载的自由函数也可以工作,而且更容易理解:
template <typename T>
std::shared_ptr<T> resolve_pointer(std::shared_ptr<T> & p) {
return p;
}
template <typename T>
std::shared_ptr<T> resolve_pointer(std::weak_ptr<T> & p) {
return p.lock();
}
如果您的目标是能够扩展您的代码以提供与任何 strong/weak 指针对的互操作性,这些指针对具有已实现的动态转换操作(此处显示 std::strong/weak_ptr 和 boost ::strong/weak_ptr),你可以使用一组特征来做到这一点,就像这样......当心,前方有龙:
// Defines a resolve static function to get a strong pointer from either
// a strong or a weak pointer.
template <typename T>
struct smart_pointer_info;
template <typename T>
struct smart_pointer_info<std::shared_ptr<T>>
{
typedef std::shared_ptr<T> ptr_type;
typedef T element_type;
typedef std::shared_ptr<T> resolved_type;
static resolved_type resolve(ptr_type & p) {
return p;
}
};
template <typename T>
struct smart_pointer_info<std::weak_ptr<T>>
{
typedef std::weak_ptr<T> ptr_type;
typedef T element_type;
typedef std::shared_ptr<T> resolved_type;
static resolved_type resolve(ptr_type & p) {
return p.lock();
}
};
template <typename T>
struct smart_pointer_info<boost::shared_ptr<T>>
{
typedef boost::shared_ptr<T> ptr_type;
typedef T element_type;
typedef boost::shared_ptr<T> resolved_type;
static resolved_type resolve(ptr_type & p) {
return p;
}
};
template <typename T>
struct smart_pointer_info<boost::weak_ptr<T>>
{
typedef boost::weak_ptr<T> ptr_type;
typedef T element_type;
typedef boost::shared_ptr<T> resolved_type;
static resolved_type resolve(ptr_type & p) {
return p.lock();
}
};
// Provides a static "cast" function that converts a strong pointer T
// into a strong point that points at an object of type D.
template <typename T, typename D>
struct smart_pointer_dynamic_cast;
template <typename T, typename D>
struct smart_pointer_dynamic_cast<std::shared_ptr<T>, D>
{
typedef std::shared_ptr<T> ptr_type;
typedef std::shared_ptr<D> cast_type;
static cast_type cast(ptr_type & p) {
return std::dynamic_pointer_cast<D>(p);
}
};
template <typename T, typename D>
struct smart_pointer_dynamic_cast<boost::shared_ptr<T>, D>
{
typedef boost::shared_ptr<T> ptr_type;
typedef boost::shared_ptr<D> cast_type;
static cast_type cast(ptr_type & p) {
return boost::dynamic_pointer_cast<D>(p);
}
};
// Helper so we can omit the template parameter for the source pointer type.
template <typename D>
struct dynamic_cast_helper
{
template <typename P>
static typename smart_pointer_dynamic_cast<typename smart_pointer_info<P>::resolved_type, D>::cast_type cast(P & p) {
typename smart_pointer_info<P>::resolved_type r = smart_pointer_info<P>::resolve(p);
return smart_pointer_dynamic_cast<typename smart_pointer_info<P>::resolved_type, D>::cast(r);
}
};
// Then we might use it like so:
class A {
public:
virtual void print() {
std::cout << "A::print()" << std::endl;
}
};
class B : public A {
public:
virtual void print() {
std::cout << "B::print()" << std::endl;
}
};
int main()
{
auto x = std::make_shared<B>();
std::weak_ptr<B> xw{x};
auto y = boost::make_shared<B>();
boost::weak_ptr<B> yw{y};
dynamic_cast_helper<A>::cast(x)->print();
dynamic_cast_helper<A>::cast(xw)->print();
dynamic_cast_helper<A>::cast(y)->print();
dynamic_cast_helper<A>::cast(yw)->print();
return 0;
}
(Demo)
你的转换 dynamic_pointer_cast<typename T::element_type>(iteratableList[i])
然后变成 dynamic_cast_helper<typename smart_pointer_info<T>::element_type>::cast(iteratableList[i])
并且沿途的所有类型都被编译器推断出来。