使用模板模板参数和enable_if获得正确的过载选择

时间:2016-02-01 20:07:56

标签: c++ templates enable-if

我在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派生的东西的语法是什么?

我已经使用模板模板参数对此进行了多次尝试,但我一直在搞砸它。

1 个答案:

答案 0 :(得分:0)

让我们从测试Tshared_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_typeshared_ptr,然后再检查element_type的{​​{1}}是否来自shared_ptr。成功后,Shape的类型为enable_if,函数的返回类型将变为无效。

Live Demo

以下是测试:

void