2013-06-12 166 views
10

我想在C++ 11中重载std::is_pointer以产生std::shared_ptr<T>也是如此,因为后者的行为非常像T*C++ 11:将std :: is_pointer扩展到std :: shared_ptr

#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’ 
+3

''is_pointer'在模板编程中很有用,当我想知道某些东西是否是原始指针类型,而不仅仅是指针。如果'* p'和'++ p'是有效的表达式,你可以实现一个'is_like_ptr',它执行类似SFINAE的测试。 – aschepler

+3

@aschepler:智能指针通常不支持算术。 'is_dereferencable',只是检查'* p',可能更合适。 –

+0

好点。我觉得我还没有醒过来。 – aschepler

回答

10

std::is_pointer莫名其妙来自升压和原本打算只在这里检测原始指针和函数指针是底部注意,您可以在Boost documentation发现:

is_pointer检测到“真正的”指针类型而已,而不是聪明的指针。用户不应该为智能指针类型专门设置is_pointer,否则可能会导致Boost(和其他第三方)代码无法正常工作。希望特征检测智能指针的用户应该创建自己的指针。但是,请注意,通常无法自动检测智能指针类型,因此,对于每个支持的智能指针类型,这种特征必须部分专用。

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

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

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

+3

我认为'Dereferencable'概念更合适,因为智能指针不能递增,递减和所有其他限定随机访问迭代器的东西。 –

+0

@ArneMertz固定,谢谢:) – Morwenn

+0

我不会说它只是用于* boost * -compatibility,但是由于所有这些语言级别类型标识符的固有设计。它们被设计为识别实际类型的变量类别,而不是更高级别的语义概念。 –

4

虽然我同意,更普遍的类型特征,喜欢behaves_like_pointer (原谅愚蠢的名字),is_callable(对于全部东西有())或is_indexable(对于数组式的东西)会非常有用,那肯定不是什么东西l ike is_pointer,is_functionis_array已被设计。它们是识别实际困难语言类型的特征,与is_integral,is_classis_rvalue_reference非常相似。

因此,对于任何种类的智能指针而言,重叠is_pointer都会克服该原始目的,并且该目的是明确无误的。但我仍然同意像is_smart_pointer,is_callable,is_nothrow_swappableis_hashable等其他更一般的概念类型类别也会非常有用。

8

我想在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为真只会是错误的。

其实,我想摆在首位以下代码:

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中的模板不符合定义的语义,则不允许您将模板添加到模板中。如果T指针类型其中std::shared_ptr不是std::is_pointer<T>的语义是这样的,它仅从std::true_type派生。这本身就足够了,但在这种特殊情况下的标准实际上去禁止它明确(§20.9.2)的长度:

的程序,增加了专业化的任何定义的类模板的行为除非另有说明,在本小节中未定义。

<type_traits>中用户可以添加专精的唯一模板是std::common_type

+0

+1如果提到特殊的''类别模板(common_type'除外)是非法的。不幸的是,我见过甚至有经验的程序员都建议这样做! Obrigado。 –

+0

C++ 17结构化绑定现在也期望用户专注于''。 – user2023370

0

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

std ::中的type_traits的想法是提供原语。您可以使用那些开箱即用的方法,并且仅使用专业版来覆盖您的自定义类型,以便按照原始语义正确获取报告。

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

根据原始想法调整原件很可能会导致ODR违规,因为您如何知道链接的库尚未使用带有shared_ptr或is_pointer的is_pointer?

相关问题