use*_*436 1 c++ type-traits c++17
我需要一个 typetrait 来为以下“连续内存”类型(operator[]可以应用)返回值类型:
std::vector<T, Args...>, std::array<T, N>, T[], T[N], 和T*(可能带有 CV 限定符,如T* const)。特征应该T为所有上述类型返回。
在 C++17 中是否有比下面乏味的实现更简洁的实现?就像以某种方式将所有指针案例收集在一个专业化和应用std::remove_ptr中一样,对于T[N]with 也是如此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; };
Run Code Online (Sandbox Code Playgroud)
我需要一个 typetrait,它会返回以下“连续内存”类型的值类型(operator[] 可以应用于该类型):
要“提取”所需的类型,在我看来,您可以简单地使用它operator[]本身,删除引用、易失性和常量。请参阅以下帮助程序结构
template <typename T>
struct contained_type
{ using type = std::remove_cv_t<
std::remove_reference_t<
decltype(std::declval<T>()[0])>>; };
Run Code Online (Sandbox Code Playgroud)
您可以contained_type使用 SFINAE编写您的结构,因此使用额外的默认模板参数
template <typename, typename = void>
struct remove_array_like;
Run Code Online (Sandbox Code Playgroud)
在我看来,你只需要三个专业。
一个用于contigous内存容器(因此用于与容器data()返回一个指针contigous含有存储器的启动方法),即对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>
{ };
Run Code Online (Sandbox Code Playgroud)
一个指针
template <typename T>
struct remove_array_like<T, std::enable_if_t<std::is_pointer_v<T>>>
: public contained_type<T>
{ };
Run Code Online (Sandbox Code Playgroud)
一个用于数组
template <typename T>
struct remove_array_like<T, std::enable_if_t<std::is_array_v<T>>>
: public contained_type<T>
{ };
Run Code Online (Sandbox Code Playgroud)
下面是一个完整的编译 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> );
}
Run Code Online (Sandbox Code Playgroud)
从 C++20 开始就可以使用std::remove_cvref,所以contained_type可以简化如下
template <typename T>
struct contained_type
{ using type = std::remove_cvref_t<
decltype(std::declval<T>()[0])>; };
Run Code Online (Sandbox Code Playgroud)