Typetrait 获取连续内存容器的值类型
Typetrait to get value type of contiguous-memory containers
我需要一个类型特征,它将 return 值类型用于以下“连续内存”类型(可以应用 operator[]
):
std::vector<T, Args...>
、std::array<T, N>
、T[]
、T[N]
和 T*
(可能带有 CV 限定符,如 T* const
)。对于上述所有类型,特征应该 return T
。
在C++17中有没有比下面繁琐的实现更简洁的实现?就像以某种方式在一个专业化中收集所有指针案例并应用 std::remove_ptr
,与 T[N]
和 std::remove_extent
相同。
template<class T> struct remove_array_like;
template<class T> struct remove_array_like<T*> { using type = T; };
template<class T> struct remove_array_like<T* const> { using type = T; };
template<class T> struct remove_array_like<T* volatile> { using type = T; };
template<class T> struct remove_array_like<T* const volatile> { using type = T; };
template<class T> struct remove_array_like<T[]> { using type = T; };
template<class T, std::size_t N>
struct remove_array_like<T[N]> { using type = T; };
template<class T, std::size_t N>
struct remove_array_like<std::array<T, N>> { using type = T; };
template<class T, class... Args>
struct remove_array_like<std::vector<T, Args...>> { using type = T; };
I need a typetrait that would return value type for the following "contiguous-memory" types (to which operator[] can be applied):
要“提取”所需的类型,在我看来您可以简单地使用 operator[]
本身,删除引用、volatiles 和 const。请参阅以下帮助程序结构
template <typename T>
struct contained_type
{ using type = std::remove_cv_t<
std::remove_reference_t<
decltype(std::declval<T>()[0])>>; };
您可以使用 SFINAE 编写 contained_type
结构,因此需要额外的默认模板参数
template <typename, typename = void>
struct remove_array_like;
在我看来,您只需要三个专业。
一个用于连续内存容器(因此对于具有 data()
方法的容器,return 一个指向连续内存开始的指针),即用于 std::vector
, std::array
、std::string
等字符串类型
template <typename T>
struct remove_array_like<T, std::void_t<decltype(std::declval<T>().data())>>
: public contained_type<T>
{ };
一个用于指点
template <typename T>
struct remove_array_like<T, std::enable_if_t<std::is_pointer_v<T>>>
: public contained_type<T>
{ };
还有一个用于数组
template <typename T>
struct remove_array_like<T, std::enable_if_t<std::is_array_v<T>>>
: public contained_type<T>
{ };
下面是一个完整的编译C++17的例子
#include <set>
#include <array>
#include <deque>
#include <vector>
#include <string>
#include <type_traits>
template <typename T>
struct contained_type
{ using type = std::remove_cv_t<
std::remove_reference_t<
decltype(std::declval<T>()[0])>>; };
template <typename, typename = void>
struct remove_array_like;
template <typename T>
struct remove_array_like<T, std::void_t<decltype(std::declval<T>().data())>>
: public contained_type<T>
{ };
template <typename T>
struct remove_array_like<T, std::enable_if_t<std::is_pointer_v<T>>>
: public contained_type<T>
{ };
template <typename T>
struct remove_array_like<T, std::enable_if_t<std::is_array_v<T>>>
: public contained_type<T>
{ };
int main ()
{
using T1 = remove_array_like<std::vector<int>>::type;
//using T2 = remove_array_like<std::deque<int>>::type; // error! no data(), no contigous
using T3 = remove_array_like<std::array<int, 1u>>::type;
using T4 = remove_array_like<std::string>::type;
using T5 = remove_array_like<int * volatile>::type;
using T6 = remove_array_like<int const [1u]>::type;
using T7 = remove_array_like<int volatile []>::type;
// using T8 = remove_array_like<std::set<int>>::type; // error!
// using T9 = remove_array_like<int>::type; // error!
static_assert( std::is_same_v<T1, int> );
static_assert( std::is_same_v<T3, int> );
static_assert( std::is_same_v<T4, char> );
static_assert( std::is_same_v<T5, int> );
static_assert( std::is_same_v<T6, int> );
static_assert( std::is_same_v<T7, int> );
}
从C++20开始可以使用std::remove_cvref
,所以contained_type
可以简化如下
template <typename T>
struct contained_type
{ using type = std::remove_cvref_t<
decltype(std::declval<T>()[0])>; };
我需要一个类型特征,它将 return 值类型用于以下“连续内存”类型(可以应用 operator[]
):
std::vector<T, Args...>
、std::array<T, N>
、T[]
、T[N]
和 T*
(可能带有 CV 限定符,如 T* const
)。对于上述所有类型,特征应该 return T
。
在C++17中有没有比下面繁琐的实现更简洁的实现?就像以某种方式在一个专业化中收集所有指针案例并应用 std::remove_ptr
,与 T[N]
和 std::remove_extent
相同。
template<class T> struct remove_array_like;
template<class T> struct remove_array_like<T*> { using type = T; };
template<class T> struct remove_array_like<T* const> { using type = T; };
template<class T> struct remove_array_like<T* volatile> { using type = T; };
template<class T> struct remove_array_like<T* const volatile> { using type = T; };
template<class T> struct remove_array_like<T[]> { using type = T; };
template<class T, std::size_t N>
struct remove_array_like<T[N]> { using type = T; };
template<class T, std::size_t N>
struct remove_array_like<std::array<T, N>> { using type = T; };
template<class T, class... Args>
struct remove_array_like<std::vector<T, Args...>> { using type = T; };
I need a typetrait that would return value type for the following "contiguous-memory" types (to which operator[] can be applied):
要“提取”所需的类型,在我看来您可以简单地使用 operator[]
本身,删除引用、volatiles 和 const。请参阅以下帮助程序结构
template <typename T>
struct contained_type
{ using type = std::remove_cv_t<
std::remove_reference_t<
decltype(std::declval<T>()[0])>>; };
您可以使用 SFINAE 编写 contained_type
结构,因此需要额外的默认模板参数
template <typename, typename = void>
struct remove_array_like;
在我看来,您只需要三个专业。
一个用于连续内存容器(因此对于具有 data()
方法的容器,return 一个指向连续内存开始的指针),即用于 std::vector
, std::array
、std::string
等字符串类型
template <typename T>
struct remove_array_like<T, std::void_t<decltype(std::declval<T>().data())>>
: public contained_type<T>
{ };
一个用于指点
template <typename T>
struct remove_array_like<T, std::enable_if_t<std::is_pointer_v<T>>>
: public contained_type<T>
{ };
还有一个用于数组
template <typename T>
struct remove_array_like<T, std::enable_if_t<std::is_array_v<T>>>
: public contained_type<T>
{ };
下面是一个完整的编译C++17的例子
#include <set>
#include <array>
#include <deque>
#include <vector>
#include <string>
#include <type_traits>
template <typename T>
struct contained_type
{ using type = std::remove_cv_t<
std::remove_reference_t<
decltype(std::declval<T>()[0])>>; };
template <typename, typename = void>
struct remove_array_like;
template <typename T>
struct remove_array_like<T, std::void_t<decltype(std::declval<T>().data())>>
: public contained_type<T>
{ };
template <typename T>
struct remove_array_like<T, std::enable_if_t<std::is_pointer_v<T>>>
: public contained_type<T>
{ };
template <typename T>
struct remove_array_like<T, std::enable_if_t<std::is_array_v<T>>>
: public contained_type<T>
{ };
int main ()
{
using T1 = remove_array_like<std::vector<int>>::type;
//using T2 = remove_array_like<std::deque<int>>::type; // error! no data(), no contigous
using T3 = remove_array_like<std::array<int, 1u>>::type;
using T4 = remove_array_like<std::string>::type;
using T5 = remove_array_like<int * volatile>::type;
using T6 = remove_array_like<int const [1u]>::type;
using T7 = remove_array_like<int volatile []>::type;
// using T8 = remove_array_like<std::set<int>>::type; // error!
// using T9 = remove_array_like<int>::type; // error!
static_assert( std::is_same_v<T1, int> );
static_assert( std::is_same_v<T3, int> );
static_assert( std::is_same_v<T4, char> );
static_assert( std::is_same_v<T5, int> );
static_assert( std::is_same_v<T6, int> );
static_assert( std::is_same_v<T7, int> );
}
从C++20开始可以使用std::remove_cvref
,所以contained_type
可以简化如下
template <typename T>
struct contained_type
{ using type = std::remove_cvref_t<
decltype(std::declval<T>()[0])>; };