如何将任何化合物还原为非化合物类型

时间:2018-08-17 16:33:39

标签: c++ c++17 c++20

要求:给定复合类型'T',用作基础类型的非复合类型是什么?

到目前为止,我的尝试是此模板别名:

template <class T>
using reduce_to_non_compound_t = 
    std::remove_all_extents_t< 
       std::remove_pointer_t< 
         std::remove_cvref_t < T > 
     > >;

例如

  // array of pointers to string
    using arr_of_sp = std::string * (&)[42];

  // should pass
  static_assert( std::is_same_v<
       std::string,
        reduce_to_non_compound_t<arr_of_sp>
   >  )

许多用例来测试这一点可能非常大。在进一步介绍之前,我想问问是否有人有更好的主意甚至实施?

我在问这样的事情是否合乎逻辑。这是用例的来龙去脉。如果这是合乎逻辑的,则可以编写它。

2 个答案:

答案 0 :(得分:2)

如果您只是说要从类型中剥离cv限定词,指针,引用和范围,那么可以使用以下方法:

template <typename T, typename = void> struct base {using type = std::remove_cv_t<T>;};

template <typename T> using base_t = typename base<T>::type;

template <typename T> struct base<T, std::enable_if_t<std::is_array_v<T>>>
{using type = base_t<std::remove_all_extents_t<T>>;};

template <typename T> struct base<T, std::enable_if_t<std::is_reference_v<T>>> 
{using type = base_t<std::remove_reference_t<T>>;};

template <typename T> struct base<T, std::enable_if_t<std::is_pointer_v<T>>> 
{using type = base_t<std::remove_pointer_t<T>>;};

用法:

static_assert(std::is_same_v<int, base_t<const int *volatile[4]>>);

可以轻松扩展以与成员函数指针,函数或其他功能一起使用。

答案 1 :(得分:0)

我可能会谦虚地报告,我所建议的(在问题中)解决方案确实有效。

特别感谢Holy Black Cat先生发现了一个缺陷,因此我添加了'dbj :: remove_all_ptr_t`。现在,解决方案现在也适用于双精度指针,三重指针等。

Wandbox is here

    namespace dbj 
{
    template <typename T> struct remove_all_ptr { typedef T type;   };

    template <typename T> struct remove_all_ptr<T*> {
        using type = typename remove_all_ptr<std::remove_cv_t<T>>::type;
    };

    template <typename T>
    using remove_all_ptr_t = typename remove_all_ptr<T>::type ;

template< class T >
struct remove_cvref {
    typedef std::remove_cv_t<std::remove_reference_t<T>> type;
};

template< class T >
using remove_cvref_t = typename remove_cvref<T>::type;

template <class T>
using to_base_t =
  remove_all_ptr_t< std::remove_all_extents_t< remove_cvref_t < T > > >;

} // dbj

Holy Black Cat先生的解决方案也起作用。尽管有些人可能会觉得它有些复杂(我个人认为并非如此)。

我的解决方案在名称空间dbj中,而他的解决方案在名称空间hbc中。这是我的快速测试。

// testing
static_assert(std::is_same_v<std::string, hbc::base_t<std::string * (&)[42]>>);
static_assert(std::is_same_v<std::string ,dbj::to_base_t<std::string * (&)[42]>>);

static_assert(std::is_same_v<void (), hbc::base_t<void ()>>);
static_assert(std::is_same_v<void (), dbj::to_base_t<void ()>>);

// 
struct X { char data{}; char method () const { return {};} };
static_assert(std::is_same_v<X, hbc::base_t<X (&) []>>);
static_assert(std::is_same_v<X, dbj::to_base_t<X (&) []>>);

//
using method_t = char (X::*)() ;
static_assert(std::is_same_v<method_t, hbc::base_t< method_t (&) []>>);
static_assert(std::is_same_v<method_t, dbj::to_base_t< method_t (&) []>>);

两个解决方案都通过了上述测试。 Wandbox is here。 谢谢大家的宝贵讨论。