输入trait以获取std :: array或C-style数组的元素类型

时间:2017-06-13 12:46:57

标签: c++ templates typetraits

我想要一个类型特征来获取std::array或普通旧C风格数组的元素类型,例如。如果提供charstd::array<char, 3>,则应返回char[3]

执行此操作的机制似乎只是部分到位......我可以使用::value_type上的std::array和普通数组上的std::remove_all_extents,但我可以&#39 ;找到一个结合了两者的单一特征,我自己也不能写一个。

我已经达到了这个目的:

#include <array>
#include <type_traits>

template <class T>
using element_type =  typename std::conditional<
    std::is_array<T>::value,
    typename std::remove_all_extents<T>::type,
    typename T::value_type
>::type;

当然,它适用于std::array

int main()
{
    static_assert(
        std::is_same<char, element_type<std::array<char, 3>>>::value,
        "element_type failed");
}

但是当我传递一个普通数组时会中断,因为显然普通数组不具有::value_type

static_assert(std::is_same<char, element_type<char[3]>>::value, "element_type failed");

只会出现错误,例如&#34; &#39; T&#39;:在&#39; ::&#39; &#34;后面必须是类或命名空间,正如你所期望的那样。

如果我正在撰写函数,我会使用std::enable_if来隐藏有问题的模板实例,但我不知道如何在类型特征中使用此方法。

解决此问题的正确方法是什么?

3 个答案:

答案 0 :(得分:6)

对于非常通用解决方案,它支持std::begin支持的任何类型的容器/数组:

template<typename T>
using element_type_t = std::remove_reference_t<decltype(*std::begin(std::declval<T&>()))>;
您可能知道

std::begin返回一个迭代器。取消引用它会为您提供它的值,您可以使用decltype来获取它的类型。 std::remove_reference_t是必需的,因为迭代器返回对它们指向的元素的引用。因此,这适用于std::begin具有过载的每种类型。

答案 1 :(得分:5)

您可以在std::array和C风格的数组上调用哪些函数/运算符? operator[]当然:

template <class Array>
using array_value_type = decay_t<decltype(std::declval<Array&>()[0])>;

这适用于支持按整数查找的任何内容,包括std::vectorstd::map<std::size_t, T>等。

如果你想区分从const数组到非成本数组的内容,你可能想要创建两个类似于以下行的类型特征:

template <class Array>
using array_element_t = decay_t<decltype(std::declval<Array>()[0])>;

template <class Array>
using array_value_t   = remove_reference_t<decltype(std::declval<Array>()[0])>;

这里的第二个特征保留了传入的Array类型的常量,而第一个特征剥离了它。这些都有用例。

答案 2 :(得分:3)

执行此操作的方法是分派到专门的模板

template<typename>
struct arr_trait;

template<typename T, size_t N>
struct arr_trait<T[N]> {using type = T;};

template<typename T, size_t N>
struct arr_trait<std::array<T, N>> {using type = T;};

template<typename T>
struct arr_trait<T&> : arr_trait<T> {};

template<typename T>
struct arr_trait<T&&> : arr_trait<T> {};

template<typename T>
using element_type = typename arr_trait<T>::type;

Live

std::conditional失败的原因是因为它不支持(据我所知也不支持短路,并且两种类型都将被评估