2013-06-12 2 views
10

Я думаю о перегрузке std::is_pointer в C++ 11, чтобы получить значение true для std::shared_ptr<T>, так как последнее ведет себя очень как T*.C++ 11: расширение std :: is_pointer to 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' полезен в программировании шаблонов, когда я хочу знать, является ли что-то необработанным типом указателя, а не как указатель. Вы можете реализовать 'is_like_ptr', который делает такие вещи, как тест с SFINAE, если' * p' и '++ p' являются допустимыми выражениями. – aschepler

+3

@aschepler: Умные указатели обычно не поддерживают арифметику. 'is_dereferencable', просто проверка на' * p', может быть более подходящей. –

+0

Хорошая точка. Я не думаю, что проснулся. – aschepler

ответ

10

std::is_pointer как-то приходит от Boost, и первоначально предназначен для обнаружения сырых указателей и указателей на функции только, вот нижняя нота, которую вы можете найти в Boost documentation:

is_pointer обнаруживает «реальные» типы указателей только и не умные указатели. Пользователи не должны специализировать is_pointer для типов интеллектуальных указателей, так как это может привести к тому, что код Boost (и другой сторонний) не будет работать правильно. Пользователи, которым нужна черта для обнаружения интеллектуальных указателей, должны создавать свои собственные. Тем не менее, обратите внимание, что вообще нет способа автоматически определять магические типы указателей, поэтому такой признак должен быть частично специализированным для каждого поддерживаемого типа интеллектуального указателя.

Возможно, они просто так себя чувствовали в стандартной библиотеке, чтобы поддерживать низкий уровень удивления для пользователей, которые уже использовали его. В любом случае, как вы только что продемонстрировали это, легко создать свою собственную черту для обнаружения интеллектуальных указателей.

В общем, то, что вы ищете, было бы признаком того, что будет искать типы, которые реализуют концепцию Dereferenceable (хотя эта работа также будет работать для std::optional, а не только указателей/умных указателей).

И для полноты конструкции Boost is_pointer существует возможность обнаруживать только необработанные указатели, а не указательные классы. Но другие ответы уже должны дать вам довольно хорошую информацию об этом.

+3

Я думаю, что концепция' Dereferencable' более приемлема, поскольку интеллектуальные указатели не являются инкрементными, уменьшающимися и все другие вещи, которые квалифицируют итераторы произвольного доступа. –

+0

@ArneMertz Исправлено, спасибо :) – Morwenn

+0

Я бы не сказал, что это просто для * boost * -совместимости, но из-за присущего дизайну всех этих идентификаторов категорий типа языкового уровня. Они предназначены для определения фактических категорий категорий переменных в отличие от семантических концепций более высокого уровня. –

4

Хотя я согласен, что черты более общего типа, как behaves_like_pointer (извините глупое имя), is_callable (для все вещи, имеющие ()) или is_indexable (для массивных вещей) были бы очень полезными, это, конечно, не то, что вещи l ike is_pointer, is_function или is_array предназначены для. Это черты, определяющие актуальные типы типов жестокого языка, почти такие же, как is_integral, is_class или is_rvalue_reference.

Таким образом, перерасход is_pointer для любого умного указателя будет соглашаться с этой первоначальной целью, и эта цель является четкой и недвусмысленной. Но я по-прежнему согласен с тем, что дополнительные более общие концептуальные категории типа, такие как is_smart_pointer, is_callable, is_nothrow_swappable или is_hashable, также очень полезны.

8

Я думаю о перегрузке std :: is_pointer в C++ 11, чтобы дать true для std :: shared_ptr, так как последнее ведет себя очень как 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> такова, что она получена только от std::true_type, если T является указателем типа, который std::shared_ptr не является. Это само по себе было бы достаточно, но в данном конкретном случае стандарт фактически идет к длине запрещая его явно (§20.9.2):

Поведения программы, которая добавляет специализации для любого из шаблонов классов, определенных в этом подпункте не определено, если не указано иное.

Единственный шаблон от <type_traits>, которым пользователь может добавить специализации: std::common_type.

+0

+1 Заметим, что специализация '' classe templates (за исключением 'common_type') является незаконной. К сожалению, я видел даже опытных программистов, предлагающих это сделать! Obrigado. –

+0

C++ 17 структурированные привязки теперь также ожидают, что пользователь специализируется на ''. – user2023370

0

Другие ответы покрывали технические детали и некоторые фон.

Идея type_traits в std :: заключается в предоставлении примитивов. Вы используете их из коробки и делаете специализации только, чтобы покрыть свои самоопределяемые типы, чтобы следить за правильными отчетами для исходной семантики.

То, что вы действительно хотите (IMO), не отвлекает шаблон is_pointer, а имеет функцию запроса, которая скрывает вашу семантику. Вот что вы должны делать: ваш собственный is_maybesmart_pointer <>, который сообщает true для оригинальных указателей и всего, что вы хотите. И используйте это в своем коде.

Тонкая настройка оригинала по оригинальной идее вполне может привести к нарушению ODR, так как вы знаете, что ссылки, которые вы связываете, еще не использовали is_pointer с shared_ptr или что-то в этом роде?

Смежные вопросы