• 用元编程来判断STL类型


      在此之前,先来回顾元编程当中的一个重要概念。

    template<typename _Tp, _Tp __v>
        struct integral_constant
        {
          static constexpr _Tp                  value = __v;
          typedef _Tp                           value_type;
          typedef integral_constant<_Tp, __v>   type;
          constexpr operator value_type() const noexcept { return value; }
    #if __cplusplus > 201103L
    
    #define __cpp_lib_integral_constant_callable 201304L
    
          constexpr value_type operator()() const noexcept { return value; }
    #endif
        };
    
      /// The type used as a compile-time boolean with true value.
      using true_type =  integral_constant<bool, true>;
    
      /// The type used as a compile-time boolean with false value.
      using false_type = integral_constant<bool, false>;

      std::true_type和std::false_type其实就是std::integral_constant传入模板特定参数的情形,注意到integral_constant结构体当中的value_type,顾名思义指的是值的类型,对应到std::true_type和std::false_type就是true和false。

      先尝试着来写一个对std::vector的判断。

    // vector
    template <typename _Tp>
    struct is_vector : std::false_type{};
    
    template <typename _Tp>
    struct is_vector<std::vector<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_vector_v = is_vector<container_type>::value;
    
    int main() {
        std::vector<int> v1;
        std::vector<double> v2;
        std::vector<std::queue<int>> v3;
        
        std::cout << is_vector_v<decltype(v1)> << '\n';
        std::cout << is_vector_v<decltype(v2)> << '\n';
        std::cout << is_vector_v<decltype(v3)> << "\n\n";
    
        std::queue<int> q1;
        std::queue<double> q2;
        std::queue<std::vector<int>> q3;
    
        std::cout << is_vector_v<decltype(q1)> << '\n';
        std::cout << is_vector_v<decltype(q2)> << '\n';
        std::cout << is_vector_v<decltype(q3)> << '\n';
    }

      到这里还比较容易,用上面所讲到的std::true_type对is_vector模板类进行特化。拓展到全体STL容器类型,我们可以往此方向进行延申,对其它STL容器反复操作。

    // vector
    template <typename _Tp>
    struct is_vector : std::false_type{};
    
    template <typename _Tp>
    struct is_vector<std::vector<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_vector_v = is_vector<container_type>::value;
    
    // queue
    template <typename _Tp>
    struct is_queue : std::false_type{};
    
    template <typename _Tp>
    struct is_queue<std::queue<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_queue_v = is_queue<container_type>::value;
    
    // string
    template <typename _Tp>
    struct is_string : std::false_type{};
    
    template <>
    struct is_string<std::string> : std::true_type{};
    
    template <typename container_type>
    bool is_string_v = is_string<container_type>::value;
    
    // array
    template <typename _Tp>
    struct is_array : std::false_type{};
    
    template <typename _Tp, std::size_t N>
    struct is_array<std::array<_Tp, N>> : std::true_type{};
    
    template <typename container_type>
    bool is_array_v = is_array<container_type>::value;
    
    // priority_queue
    template <typename _Tp>
    struct is_priority_queue : std::false_type{};
    
    template <typename _Tp>
    struct is_priority_queue<std::priority_queue<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_priority_queue_v = is_priority_queue<container_type>::value;
    
    // map
    template <typename _Tp>
    struct is_map : std::false_type{};
    
    template <typename _Tp, typename _Up>
    struct is_map<std::map<_Tp, _Up>> : std::true_type{};
    
    template <typename container_type>
    bool is_map_v = is_map<container_type>::value;
    
    // unordered_map
    template <typename _Tp>
    struct is_unordered_map : std::false_type{};
    
    template <typename _Tp, typename _Up>
    struct is_unordered_map<std::unordered_map<_Tp, _Up>> : std::true_type{};
    
    template <typename container_type>
    bool is_unordered_map_v = is_unordered_map<container_type>::value;
    
    // multimap
    template <typename _Tp>
    struct is_multimap : std::false_type{};
    
    template <typename _Tp, typename _Up>
    struct is_multimap<std::multimap<_Tp, _Up>> : std::true_type{};
    
    template <typename container_type>
    bool is_multimap_v = is_multimap<container_type>::value;
    
    // unordered_multimap
    template <typename _Tp>
    struct is_unordered_multimap : std::false_type{};
    
    template <typename _Tp, typename _Up>
    struct is_unordered_multimap<std::unordered_multimap<_Tp, _Up>> : std::true_type{};
    
    template <typename container_type>
    bool is_unordered_multimap_v = is_unordered_multimap<container_type>::value;
    
    // set
    template <typename _Tp>
    struct is_set : std::false_type{};
    
    template <typename _Tp>
    struct is_set<std::set<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_set_v = is_set<container_type>::value;
    
    // unordered_set
    template <typename _Tp>
    struct is_unordered_set : std::false_type{};
    
    template <typename _Tp>
    struct is_unordered_set<std::unordered_set<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_unordered_set_v = is_unordered_set<container_type>::value;
    
    // multiset
    template <typename _Tp>
    struct is_multiset : std::false_type{};
    
    template <typename _Tp>
    struct is_multiset<std::multiset<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_multiset_v = is_multiset<container_type>::value;
    
    // unordered_multiset
    template <typename _Tp>
    struct is_unordered_multiset : std::false_type{};
    
    template <typename _Tp>
    struct is_unordered_multiset<std::unordered_multiset<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_unordered_multiset_v = is_unordered_multiset<container_type>::value;
    
    // list
    template <typename _Tp>
    struct is_list : std::false_type{};
    
    template <typename _Tp>
    struct is_list<std::list<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_list_v = is_list<container_type>::value;
    
    // forward_list
    template <typename _Tp>
    struct is_forward_list : std::false_type{};
    
    template <typename _Tp>
    struct is_forward_list<std::forward_list<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_forward_list_v = is_forward_list<container_type>::value;
    
    // stack
    template <typename _Tp>
    struct is_stack : std::false_type{};
    
    template <typename _Tp>
    struct is_stack<std::stack<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_stack_v = is_stack<container_type>::value;
    
    // deque
    template <typename _Tp>
    struct is_deque : std::false_type{};
    
    template <typename _Tp>
    struct is_deque<std::deque<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_deque_v = is_deque<container_type>::value;

      (可能会有遗漏,我对STL的理解就是上面这些)好,接下来可以定义对STL类型判断的bool变量了。

    // STL
    template <typename _Tp>
    bool is_stl_v = is_vector_v<_Tp>                ||
                    is_array_v<_Tp>                 ||
                    is_queue_v<_Tp>                 ||
                    is_deque_v<_Tp>                 || 
                    is_set_v<_Tp>                   ||
                    is_unordered_set_v<_Tp>         ||
                    is_multiset_v<_Tp>              ||
                    is_unordered_multiset_v<_Tp>    ||
                    is_map_v<_Tp>                   ||
                    is_unordered_map_v<_Tp>         ||
                    is_multimap_v<_Tp>              ||
                    is_unordered_multimap_v<_Tp>    ||
                    is_stack_v<_Tp>                 ||
                    is_string_v<_Tp>                ||
                    is_priority_queue_v<_Tp>        ||
                    is_list_v<_Tp>                  ||
                    is_forward_list_v<_Tp>;

      接下来测试一下(其实不难理解,就是写起来比较费劲)。

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    // vector
    template <typename _Tp>
    struct is_vector : std::false_type{};
    
    template <typename _Tp>
    struct is_vector<std::vector<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_vector_v = is_vector<container_type>::value;
    
    // queue
    template <typename _Tp>
    struct is_queue : std::false_type{};
    
    template <typename _Tp>
    struct is_queue<std::queue<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_queue_v = is_queue<container_type>::value;
    
    // string
    template <typename _Tp>
    struct is_string : std::false_type{};
    
    template <>
    struct is_string<std::string> : std::true_type{};
    
    template <typename container_type>
    bool is_string_v = is_string<container_type>::value;
    
    // array
    template <typename _Tp>
    struct is_array : std::false_type{};
    
    template <typename _Tp, std::size_t N>
    struct is_array<std::array<_Tp, N>> : std::true_type{};
    
    template <typename container_type>
    bool is_array_v = is_array<container_type>::value;
    
    // priority_queue
    template <typename _Tp>
    struct is_priority_queue : std::false_type{};
    
    template <typename _Tp>
    struct is_priority_queue<std::priority_queue<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_priority_queue_v = is_priority_queue<container_type>::value;
    
    // map
    template <typename _Tp>
    struct is_map : std::false_type{};
    
    template <typename _Tp, typename _Up>
    struct is_map<std::map<_Tp, _Up>> : std::true_type{};
    
    template <typename container_type>
    bool is_map_v = is_map<container_type>::value;
    
    // unordered_map
    template <typename _Tp>
    struct is_unordered_map : std::false_type{};
    
    template <typename _Tp, typename _Up>
    struct is_unordered_map<std::unordered_map<_Tp, _Up>> : std::true_type{};
    
    template <typename container_type>
    bool is_unordered_map_v = is_unordered_map<container_type>::value;
    
    // multimap
    template <typename _Tp>
    struct is_multimap : std::false_type{};
    
    template <typename _Tp, typename _Up>
    struct is_multimap<std::multimap<_Tp, _Up>> : std::true_type{};
    
    template <typename container_type>
    bool is_multimap_v = is_multimap<container_type>::value;
    
    // unordered_multimap
    template <typename _Tp>
    struct is_unordered_multimap : std::false_type{};
    
    template <typename _Tp, typename _Up>
    struct is_unordered_multimap<std::unordered_multimap<_Tp, _Up>> : std::true_type{};
    
    template <typename container_type>
    bool is_unordered_multimap_v = is_unordered_multimap<container_type>::value;
    
    // set
    template <typename _Tp>
    struct is_set : std::false_type{};
    
    template <typename _Tp>
    struct is_set<std::set<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_set_v = is_set<container_type>::value;
    
    // unordered_set
    template <typename _Tp>
    struct is_unordered_set : std::false_type{};
    
    template <typename _Tp>
    struct is_unordered_set<std::unordered_set<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_unordered_set_v = is_unordered_set<container_type>::value;
    
    // multiset
    template <typename _Tp>
    struct is_multiset : std::false_type{};
    
    template <typename _Tp>
    struct is_multiset<std::multiset<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_multiset_v = is_multiset<container_type>::value;
    
    // unordered_multiset
    template <typename _Tp>
    struct is_unordered_multiset : std::false_type{};
    
    template <typename _Tp>
    struct is_unordered_multiset<std::unordered_multiset<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_unordered_multiset_v = is_unordered_multiset<container_type>::value;
    
    // list
    template <typename _Tp>
    struct is_list : std::false_type{};
    
    template <typename _Tp>
    struct is_list<std::list<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_list_v = is_list<container_type>::value;
    
    // forward_list
    template <typename _Tp>
    struct is_forward_list : std::false_type{};
    
    template <typename _Tp>
    struct is_forward_list<std::forward_list<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_forward_list_v = is_forward_list<container_type>::value;
    
    // stack
    template <typename _Tp>
    struct is_stack : std::false_type{};
    
    template <typename _Tp>
    struct is_stack<std::stack<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_stack_v = is_stack<container_type>::value;
    
    // deque
    template <typename _Tp>
    struct is_deque : std::false_type{};
    
    template <typename _Tp>
    struct is_deque<std::deque<_Tp>> : std::true_type{};
    
    template <typename container_type>
    bool is_deque_v = is_deque<container_type>::value;
    
    // STL
    template <typename _Tp>
    bool is_stl_v = is_vector_v<_Tp>                ||
                    is_array_v<_Tp>                 ||
                    is_queue_v<_Tp>                 ||
                    is_deque_v<_Tp>                 || 
                    is_set_v<_Tp>                   ||
                    is_unordered_set_v<_Tp>         ||
                    is_multiset_v<_Tp>              ||
                    is_unordered_multiset_v<_Tp>    ||
                    is_map_v<_Tp>                   ||
                    is_unordered_map_v<_Tp>         ||
                    is_multimap_v<_Tp>              ||
                    is_unordered_multimap_v<_Tp>    ||
                    is_stack_v<_Tp>                 ||
                    is_string_v<_Tp>                ||
                    is_priority_queue_v<_Tp>        ||
                    is_list_v<_Tp>                  ||
                    is_forward_list_v<_Tp>;     
    
    struct Node {
        int a;
        int b;
    };
    
    int main() {
        std::cout << std::boolalpha;
        std::cout << is_stl_v<std::vector<int>> << '\n';
        std::cout << is_stl_v<std::queue<int>> << '\n';
        std::cout << is_stl_v<std::deque<int>> << '\n';
        std::cout << is_stl_v<std::list<int>> << '\n';
        std::cout << is_stl_v<std::forward_list<int>> << '\n';
        std::cout << is_stl_v<std::array<int, 3>> << '\n';
        std::cout << is_stl_v<std::priority_queue<int>> << '\n';
        std::cout << is_stl_v<std::stack<int>> << '\n';
        std::cout << is_stl_v<std::map<int, int>> << '\n';
        std::cout << is_stl_v<std::unordered_map<int, int>> << '\n';
        std::cout << is_stl_v<std::multimap<int, int>> << '\n';
        std::cout << is_stl_v<std::unordered_multimap<int, int>> << '\n';
        std::cout << is_stl_v<std::set<int>> << '\n';
        std::cout << is_stl_v<std::unordered_set<int>> << '\n';
        std::cout << is_stl_v<std::multiset<int>> << '\n';
        std::cout << is_stl_v<std::unordered_multiset<int>> << '\n';
        std::cout << is_stl_v<std::string> << '\n';
        std::cout << is_stl_v<int> << '\n';
        std::cout << is_stl_v<Node> << '\n';
    }

      吃饭去了。

  • 相关阅读:
    Angular 使用教程——基本语法和双向数据绑定
    ython + Selenium Web自动化 2022更新版教程 自动化测试 软件测试 爬虫-笔记博客整理
    MIMO信道的随机性
    Mysql面试
    计算机毕设(附源码)JAVA-SSM基于框架的在线问答平台
    ElasticSearch入门笔记
    对象分配规则
    我用ChatGPT写了一个简单的Python自动化测试脚本
    基于Python+Pytest+Playwright+BDD的UI自动化测试框架
    Element UI库 之 el-input 赋值后不能删除,修改,输入
  • 原文地址:https://www.cnblogs.com/ChebyshevTST/p/17891215.html