C ++ 11:将std :: is_pointer扩展为std :: shared_ptr

时间:2013-06-12 12:37:44

标签: c++ templates c++11 shared-ptr typetraits

我认为在C ++ 11中重载std::is_pointer以使std::shared_ptr<T>也为true,因为后者的行为非常像T*

#include <type_traits>

namespace std {

template <typename T> struct is_pointer<shared_ptr<T>> : std::true_type {};
template <typename T> struct is_pointer<shared_ptr<T const>> : std::true_type {};

}

我想知道为什么这个重载还没有包含在标准实现中。我有一个陷阱吗?

作为替代方案,当然可以引入新的特征is_shared_ptr<T>

实际上,我首先尝试了以下代码:

template <typename T> 
struct is_pointer<shared_ptr<typename std::remove_cv<T>::type>>
  : std::true_type 
{};
由于

无法使用GCC 4.7进行编译

error: template parameters not used in partial specialization:
error:         ‘T’

4 个答案:

答案 0 :(得分:12)

std::is_pointer以某种方式来自Boost,最初仅用于检测原始指针和函数指针,这是您可以在Boost documentation中找到的底部注释:

  

is_pointer仅检测“真实”指针类型,而不是智能指针。用户不应该专门针对智能指针类型使用is_pointer,因为这样做可能会导致Boost(和其他第三方)代码无法正常运行。想要特征检测智能指针的用户应该创建自己的特征。但是,请注意,通常无法自动神奇地检测智能指针类型,因此对于每个支持的智能指针类型,此类特征必须部分专用。

他们可能只是在标准库中表现得像兼容性,以便为已经使用它的用户保持低水平的惊喜。无论如何,正如您刚刚演示的那样,很容易创建自己的特征来检测智能指针。

基本上,你正在寻找的是一个特征,它会寻找实现Dereferenceable概念的类型(即使这个类型也适用于std::optional而不仅仅是指针/智能指针)。

为了完整起见,Boost的is_pointer设计只能检测原始指针而不是指针类。但其他答案应该已经为您提供了一些非常好的信息。

答案 1 :(得分:9)

  

我认为在C ++ 11中重载std :: is_pointer也会为std :: shared_ptr产生true,因为后者的行为非常像T *。

没有。祝++pp[i]shared_ptr一起好运。

  

我想知道为什么这个重载还没有包含在标准实现中。我有一个陷阱吗?

它没有被包含,因为它本来就是错误的:is_pointer告诉你类型是否是指针类型(§3.9.2)。 shared_ptr不是指针类型,因此将is_pointer<shared_ptr<int>::value设为true只会出错。

  

实际上,我首先尝试了以下代码:

template <typename T> 
struct is_pointer<shared_ptr<typename std::remove_cv<T>::type>>
  : std::true_type 
{};

到底在那里做remove_cv到底是怎么回事?以下“在GCC中有效”。

template <typename T> 
struct is_pointer<shared_ptr<T>>
  : std::true_type 
{};

但是,它有未定义的行为。通常,如果它们与定义的语义不一致,则不允许向名称空间std中的模板添加特化。 std::is_pointer<T>的语义是这样的,如果std::true_type指针类型T不是std::shared_ptr,它只会从<type_traits>派生。仅这一点就足够了,但在这种特殊情况下,标准实际上达到了明确禁止它的程度(§20.9.2):

  

除非另有说明,否则为本子条款中定义的任何类模板添加特殊化的程序的行为是未定义的。

std::common_type中唯一一个用户可以添加特化的模板是{{1}}。

答案 2 :(得分:5)

虽然我同意更常见的类型特征,例如behaves_like_pointer(请原谅愚蠢的名字),is_callable(对于所有具有()的内容)或{ {1}}(对于类似数组的东西)非常有用,肯定不是is_indexableis_pointeris_function之类的东西。它们是识别实际硬语言类型类别的特征,与is_arrayis_integralis_class非常相似。

因此,对任何类型的智能指针重叠is_rvalue_reference都会消除这个原始目的,而这个目的是明确无误的。但我仍然同意其他更常规的概念类型类别,例如is_pointeris_smart_pointeris_callableis_nothrow_swappable也非常有用。

答案 3 :(得分:0)

其他答案涵盖了技术细节和一些背景知识。

std ::中的type_traits的想法是提供原语。您可以直接使用这些内容,并仅使用 专门化来覆盖自定义类型,以便按照原始语义正确获取报告。

你真正想要的东西(IMO)没有转移is_pointer模板,而是拥有一个隐藏你的语义的查询功能。这就是你应该做的:你自己的is_maybesmart_pointer&lt;&gt;对于原始指针和您想要的任何其他内容,报告都是正确的。并在您的代码中使用它。

通过最初的想法调整原文很可能会导致ODR违规,因为你怎么知道你链接的libs还没有使用is_pointer和shared_ptr?