我想要一个类型特征来获取std::array
或普通旧C风格数组的元素类型,例如。如果提供char
或std::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
来隐藏有问题的模板实例,但我不知道如何在类型特征中使用此方法。
解决此问题的正确方法是什么?
答案 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::vector
,std::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;
std::conditional
失败的原因是因为它不支持(据我所知也不支持短路,并且两种类型都将被评估