在此之前,先來回顧超程式設計當中的一個重要概念。
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 <iostream>
#include <vector>
#include <queue>
#include <type_traits>
#include <string>
#include <array>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <list>
#include <forward_list>
#include <stack>
#include <deque>
// 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';
}
吃飯去了。