15

我考虑std::is_pointer在 C++11 中重载以产生 true for std::shared_ptr<T>,因为后者的行为非常类似于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

4 回答 4

13

std::is_pointer不知何故来自 Boost,最初是为了检测原始指针和函数指针,这是您可以在Boost 文档中找到的底部注释:

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

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

基本上,您正在寻找的是一种特征,它将寻找实现该Dereferenceable概念的类型(尽管这个特征也适用于std::optional指针/智能指针)。

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

于 2013-06-12T12:48:00.050 回答
11

我考虑在 C++11 中重载 std::is_pointer 以使 std::shared_ptr 也为 true,因为后者的行为非常类似于 T*。

它不是。祝你++p好运p[i]shared_ptr

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

它没有被包括在内,因为它完全是错误的:is_pointer告诉您类型是否是指针类型(第 3.9.2 节)。shared_ptr不是指针类型,所以is_pointer<shared_ptr<int>::value真的是错误的。

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

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>是这样的,它仅派生自ifstd::true_typeT不是的指针类型std::shared_ptr。仅此一项就足够了,但在这种特殊情况下,标准实际上达到了明确禁止它的长度(第 20.9.2 节):

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

用户可以添加专业化的唯一模板<type_traits>std::common_type.

于 2013-06-12T13:27:38.763 回答
6

虽然我同意更通用的类型特征,例如behaves_like_pointer(请原谅愚蠢的名称)、is_callable(对于所有具有 的事物())或is_indexable(对于类似数组的事物)会非常有用,但这肯定不是事物 likeis_pointeris_function设计is_array的用途。它们是识别实际硬语言类型类别的特征,与is_integral,is_classis_rvalue_reference.

因此is_pointer,对任何类型的智能指针进行重载都会与最初的目的相矛盾,而这个目的是明确而明确的。但我仍然同意其他更一般的概念类型类别,如is_smart_pointer, is_callable, is_nothrow_swappableoris_hashable也会非常有用。

于 2013-06-12T12:47:23.167 回答
0

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

std:: 中 type_traits 的想法是提供原语。您可以使用那些开箱即用的方法,并且进行专门化以涵盖您的自定义类型,以便正确获取原始语义的报告。

您真正想要的(IMO)不是转移 is_pointer 模板,而是拥有一个隐藏您的语义的查询功能。所以这就是你应该做的:你自己的 is_maybesmart_pointer<> 报告原始指针和任何你想要的东西都是真的。并在您的代码中使用它。

通过原始想法调整原始内容很可能会导致 ODR 违规,因为您如何知道您链接的库尚未使用 is_pointer 和 shared_ptr 或其他东西?

于 2013-06-12T13:38:55.310 回答