我在VS2013中有一个模板功能,用于执行任何给定对象的“深层复制”。一个重载是普通类型只调用operator =。但是我也有一个重载,设计用于将shared_ptr的向量用于我自己的Shape类对象,这些对象只能通过调用clone()成员函数来复制。
struct Shape { virtual std::shared_ptr<Shape> clone() const = 0; };
struct Rectangle : public Shape { virtual std::shared_ptr<Shape> clone() const override; };
所以我有这个重载,编译器选择它就好了
template<class SHP>
inline std::vector<std::shared_ptr<SHP>> deep_copy(
const std::vector<std::shared_ptr<SHP>>& val,
typename std::enable_if<std::is_base_of<Shape, SHP>::value>::type** = nullptr)
{
// ... blah blah blah
}
std::vector<std::shared_ptr<Rectangle>> objects;
auto objects2 = deep_copy(objects);
然后我想改变它以获取shared_ptr的任何非键控集合(例如列表)。好的,没问题,我确实设法了......
template<class COLL>
inline COLL deep_copy(const COLL& val,
typename std::enable_if<std::is_base_of<Shape, typename COLL::value_type::element_type>::value>::type** = nullptr)
但是这种语法确实确保集合包含shared_ptr。它只是确保它的value_type有一个嵌套的element_type,它是某种Shape
所以我的问题是, 确保集合的内容实际上是std :: shared_ptr到从Shape派生的东西的语法是什么?
我已经使用模板模板参数对此进行了多次尝试,但我一直在搞砸它。
答案 0 :(得分:0)
让我们从测试T
是shared_ptr
的概念开始:
template<typename T>
struct is_shared_ptr : std::false_type{};
template<typename T>
struct is_shared_ptr<std::shared_ptr<T>> : std::true_type{};
现在像
std::cout << std::boolalpha << is_shared_ptr<std::shared_ptr<Shape>>::value << std::endl;
将输出
真
接下来,如果某些内容因使用该概念而产生true_type
,我们希望接下来检查其element type
:
template<typename T>
using element_t = typename std::decay_t<T>::element_type;
查看返回的类型是否来自Shape
。
让我们创建另一个帮助器别名来抓取集合中的value_type
:
template<typename T>
using collection_vt = typename std::decay_t<T>::value_type;
现在我们可以将这些概念合并为一个看起来非常糟糕的概念:
template<template<class...> class C, typename U, typename... A>
auto DoTheThing(const C<U, A...>& _collection) -> std::enable_if_t<
is_shared_ptr<collection_vt<decltype(_collection)>>::value &&
std::is_base_of<Shape, element_t<collection_vt<decltype(_collection)>>>::value
>
{
std::cout << _collection.size() << std::endl;
}
初始模板参数用于接受相对通用的容器。然后我们使用尾随返回类型首先确保value_type
是shared_ptr
,然后再检查element_type
的{{1}}是否来自shared_ptr
。成功后,Shape
的类型为enable_if
,函数的返回类型将变为无效。
以下是测试:
void