2016-12-02 2 views
4

С станд :: массив <> и станд :: is_array <> оба были введены в C++ 11, это кажется очень странным, что это не удается скомпилировать:Почему std :: is_array возвращает false для std :: array?

#include <array> 
#include <type_traits> 

static_assert(std::is_array<std::array<int,2>>::value); 

Есть простой способ проверить, если что-то такое массив, в том числе и возможности T[N] и std::array<T,N>?

+2

'std :: array' просто не является массивом. Они просто назвали это потому, что это более удобное имя, чем нечто вроде 'std :: array_wrapper' или' std :: better_array'. – user2357112

+0

@ user2357112: Поскольку значение 'is_array <>' было определено точно такой же версией того же языка, который определил 'array <>', понятие «массив не является массивом» кажется абсурдным, не так ли? ? –

+1

Умные указатели не передают 'is_pointer'. 'std :: is_array' был бы менее полезен, если бы он был« std :: array »с особыми номерами и создавал' std :: array' фактический массив, чтобы победить весь смысл создания 'std :: array' в первую очередь , Просто не позволяйте им путать вас. – user2357112

ответ

1

Cppreference обеспечивает эту возможную реализацию:

template<class T> 
struct is_array : std::false_type {}; 

template<class T> 
struct is_array<T[]> : std::true_type {}; 

template<class T, std::size_t N> 
struct is_array<T[N]> : std::true_type {}; 

Это не обеспечивает специализацию std::array, к сожалению. Вы можете сделать свой собственный, делая это:

template<class T> 
struct is_array : std::is_array<T> {}; 
template<class T, std::size_t N> 
struct is_array<std::array<T, N>> : std::true_type {}; 
+0

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

+0

@MM Тогда что вы предлагаете? Создание специализации непосредственно внутри 'std'? – 0x499602D2

+2

Я бы посоветовал понять, что 'std :: is_array' относится только к массивам C-стиля, а не' std :: array', и если вы хотите получить черту, которая соответствует обоим этим вещам, то создайте свой собственный признак –

4

ISO/IEC 14882: 2011, § 20.9.4.1, Таблица 47 говорит, что это:

  • Шаблон: Шаблон структура is_array;

  • Состояние: Т представляет собой тип массива (3.9.2) по известной или неизвестной степени

  • Комментарий: Шаблон класса Array (23.3.2) не является типом массива.

поэтому утверждение не должно быть выполнено.

Хотя вы могли бы специализировать is_array, как было предложено @ 0x499602D2, если вы сделали это, вы должны сделать это в другом пространстве имен, так как вы не должны пытаться изменить значение стандартизованных функций.

+0

Спасибо за ссылку. Не удалось создать код, который хотел бы отличить массивы C++ от массивов C, используя 'std :: is_class <>'? –

+0

@JohnZwinck да, можно. Я полагаю, что стандартные авторы полагали, что это было бы более полезно таким образом. – harmic

+0

@harmic. Ваш последний абзац приводит к плохо сформированной программе, никакой диагностике не требуется; специализации классов признаков в пространстве имен 'std' не должны нарушать аксиомы класса признаков, как описано в стандарте. – Yakk

1

std::is_array определен как true только для типов, которые выглядят как T[] или T[N]. std::array не входит.

std::is_arraytrue_typestd::array не соответствует указанным нормам; что сделает вашу программу плохо сформированной, никакой диагностики не требуется. При специализированных типах в пределах std результат должен соответствовать стандарту, и здесь определен конкретный стандарт. (Кроме того, делать это для других шаблонов в пределах std очень сомнительно для незаконных).

Вы можете создать свой собственный is_array черта:

namespace notstd { 
    template<class T> 
    struct is_array:std::is_array<T>{}; 
    template<class T, std::size_t N> 
    struct is_array<std::array<T,N>>:std::true_type{}; 
    // optional: 
    template<class T> 
    struct is_array<T const>:is_array<T>{}; 
    template<class T> 
    struct is_array<T volatile>:is_array<T>{}; 
    template<class T> 
    struct is_array<T volatile const>:is_array<T>{}; 
} 

notstd::is_array<T> затем использовать в других местах, чтобы обнаружить либо массивы в стиле С или C++ std::array.

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