STL设计机制之支持运算检查
文章目录
- STL设计机制之支持运算检查
- `__STL_REQUIRES`
- `_LessThanComparable`
- `_STL_ERROR::__less_than_comparable_requirement_violation`
- STL运算检查方法的特点
- `do{...}while` 的优点
- 场景1
- 场景2
- `__x = __x`
- 自己写一个运算检查
单说这个标题可能有点奇怪,但是如果我用下面的一段话给你说你大概就能明白这一篇文章在讲什么了:
sort
函数在排序之前会先进行一个检查,那就是是否支持小于运算符:
源码是这样写的:
这行代码的会对类型进行检查,看看类型是否支持小于运算,如果不支持,LSP
会直接检查并且报错。
其实,进行运算符号的支持判断并不难,我们只需要写一段对应的代码即可,但是STL中的源码就很神奇,他做到了不消耗系统资源而达到代码检查的目的。
来一起看一看他是怎么做的:
__STL_REQUIRES
先来看看这是一个什么东西:
根据编程规范,这个东西大概率是一个宏(因为他全是大写),我们跳转到源码看一看:
一看,果然是一个宏,这个代码使用一个 do{ }while
循环将其中的代码段包裹了起来,在代码中,我们使用了一个返回值为空的函数指针类型:
void (*__x)(__type_var) = __concept##_concept_specification<__type_var>::__concept##_requirment_violation; __x = __x;
宏的第一个参数很明显是一个类型,我们在外部可以传入类,第二个参数似乎是一个功能类,用于代码检查,在上层,他这里传入了一个名为 _LessThanComparable
的工具类,猜测应该是用于是否可以进行小于号运算的检查的一个工具类。
宏生成了一个函数指针,指向 _LessThanComparable
这个类中的一个成员方法 _LessThanComparable_requirement_violation
最后 __x = __x
执行了一次自己给自己赋值的操作。
_LessThanComparable
在 _LessThanComparable
中又调用了 _STL_ERROR::__less_than_comparable_requirement_violation
这个方法。
根据英文语义也能看出,这个函数的功能似乎是与STL的错误检查有关系,我们继续往下走:
_STL_ERROR::__less_than_comparable_requirement_violation
终于算是到达源码尽头了!在这个方法中,返回类型是我们传入的 _Type
也就是我们需要待比较的类型,然后使用 if
语句将他们的比较操作执行了一遍,最后返回。
如果两个对象不能比较的话,LSP
会报错,在这里,只需要调用他们的运算方法就可以达到让代码检查的目的。
那么,为什么还要大废周章的使用一个宏和函数指针呢?
在上层,还使用了 do {...} whlie
来封装代码,这样做的意义是什么呢?
STL运算检查方法的特点
do{...}while
的优点
试想如下场景:
场景1
假设你的代码前面有个函数声明,但是你忘记加分号了:
int func()
__STL_REQUESTS(..., ...)
...
这会发生什么呢?
如果没有 do{}while
这段代码不会被 LSP
发现并且报错,因为他被替换成了代码的一部分。
场景2
假设你没有 du{...}while
如果我需要让你在宏的代码中执行到一半并且退出到外层函数,你会怎么做?
答案是做不了,没有了 do{...}while
,是不可以让代码退出到外层的,因为被宏替换掉之后,这段代码会成为所谓外层函数的一部分,因此,我们需要一层类似于函数的结构将其封装起来,这个时候,do{...}while(0)
就会起到作用。
在 do{...}while(0)
中,只需要一个 break
就可以让函数停止并退出到外层函数。
do{…}while(0) 大大提高的代码的灵活性,并且减少了一语法歧义
__x = __x
这段代码的作用是什么呢?很简单,由于 __x
是一个函数指针类型,因此,如果编译器检测到一个变量初始化之后没有被使用,那么很有可能会将其优化掉。
自己写一个运算检查
以小于号比较运算检查为例子,我们可以这样来实现:
首先写一个宏:
#define __STL_REQUESTS(type, __concept) do { \function<void()> __x = __concept<type>::__operator_concept; \__x = __x; \
} while(0)
为了方便,我们之间使用 function
代替函数指针。
关于工具类:
template <typename type>
class _LessThanCompare {
public:static void __operator_concept() {function<type(type, type)> __x = __inner__operator_concept;return ;}static type __inner__operator_concept(type a, type b) {if (a < b) return a;return b;}
};
我们在函数内部进行了一次封装,这样做的目的是统一宏中 function
的模板参数。
在函数内部我们再进行不同参数类型的传参。这样就能做到类型检查啦!
来看一下效果!!
我们先设计一个没有重载小于运算的类:
class Base {
public://bool operator<(Base &obj) const {// return true;//}
};
然后在主函数中执行:
int main() {__STL_REQUESTS(Base, _LessThanCompare);
}
编译出现下面的报错:
完整错误信息其实很长:
SRL_REQUIRES.cpp: In instantiation of ‘static type _LessThanCompare<type>::__inner__operator_concept(type, type) [with type = Base]’:
SRL_REQUIRES.cpp:36:36: required from ‘static void _LessThanCompare<type>::__operator_concept() [with type = Base]’
SRL_REQUIRES.cpp:111:5: required from here
SRL_REQUIRES.cpp:40:15: error: no match for ‘operator<’ (operand types are ‘Base’ and ‘Base’)if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/bits/stl_algobase.h:64:0,from /usr/include/c++/7/bits/char_traits.h:39,from /usr/include/c++/7/ios:40,from /usr/include/c++/7/ostream:38,from /usr/include/c++/7/iostream:39,from SRL_REQUIRES.cpp:9:
/usr/include/c++/7/bits/stl_pair.h:454:5: note: candidate: template<class _T1, class _T2> constexpr bool std::operator<(const std::pair<_T1, _T2>&, const std::pair<_T1, _T2>&)operator<(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)^~~~~~~~
/usr/include/c++/7/bits/stl_pair.h:454:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::pair<_T1, _T2>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/bits/stl_algobase.h:67:0,from /usr/include/c++/7/bits/char_traits.h:39,from /usr/include/c++/7/ios:40,from /usr/include/c++/7/ostream:38,from /usr/include/c++/7/iostream:39,from SRL_REQUIRES.cpp:9:
/usr/include/c++/7/bits/stl_iterator.h:308:5: note: candidate: template<class _Iterator> bool std::operator<(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_Iterator>&)operator<(const reverse_iterator<_Iterator>& __x,^~~~~~~~
/usr/include/c++/7/bits/stl_iterator.h:308:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::reverse_iterator<_Iterator>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/bits/stl_algobase.h:67:0,from /usr/include/c++/7/bits/char_traits.h:39,from /usr/include/c++/7/ios:40,from /usr/include/c++/7/ostream:38,from /usr/include/c++/7/iostream:39,from SRL_REQUIRES.cpp:9:
/usr/include/c++/7/bits/stl_iterator.h:346:5: note: candidate: template<class _IteratorL, class _IteratorR> bool std::operator<(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_IteratorR>&)operator<(const reverse_iterator<_IteratorL>& __x,^~~~~~~~
/usr/include/c++/7/bits/stl_iterator.h:346:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::reverse_iterator<_Iterator>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/bits/stl_algobase.h:67:0,from /usr/include/c++/7/bits/char_traits.h:39,from /usr/include/c++/7/ios:40,from /usr/include/c++/7/ostream:38,from /usr/include/c++/7/iostream:39,from SRL_REQUIRES.cpp:9:
/usr/include/c++/7/bits/stl_iterator.h:1145:5: note: candidate: template<class _IteratorL, class _IteratorR> bool std::operator<(const std::move_iterator<_IteratorL>&, const std::move_iterator<_IteratorR>&)operator<(const move_iterator<_IteratorL>& __x,^~~~~~~~
/usr/include/c++/7/bits/stl_iterator.h:1145:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::move_iterator<_IteratorL>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/bits/stl_algobase.h:67:0,from /usr/include/c++/7/bits/char_traits.h:39,from /usr/include/c++/7/ios:40,from /usr/include/c++/7/ostream:38,from /usr/include/c++/7/iostream:39,from SRL_REQUIRES.cpp:9:
/usr/include/c++/7/bits/stl_iterator.h:1151:5: note: candidate: template<class _Iterator> bool std::operator<(const std::move_iterator<_IteratorL>&, const std::move_iterator<_IteratorL>&)operator<(const move_iterator<_Iterator>& __x,^~~~~~~~
/usr/include/c++/7/bits/stl_iterator.h:1151:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::move_iterator<_IteratorL>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/string:52:0,from /usr/include/c++/7/bits/locale_classes.h:40,from /usr/include/c++/7/bits/ios_base.h:41,from /usr/include/c++/7/ios:42,from /usr/include/c++/7/ostream:38,from /usr/include/c++/7/iostream:39,from SRL_REQUIRES.cpp:9:
/usr/include/c++/7/bits/basic_string.h:6094:5: note: candidate: template<class _CharT, class _Traits, class _Alloc> bool std::operator<(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&)operator<(const basic_string<_CharT, _Traits, _Alloc>& __lhs,^~~~~~~~
/usr/include/c++/7/bits/basic_string.h:6094:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/string:52:0,from /usr/include/c++/7/bits/locale_classes.h:40,from /usr/include/c++/7/bits/ios_base.h:41,from /usr/include/c++/7/ios:42,from /usr/include/c++/7/ostream:38,from /usr/include/c++/7/iostream:39,from SRL_REQUIRES.cpp:9:
/usr/include/c++/7/bits/basic_string.h:6107:5: note: candidate: template<class _CharT, class _Traits, class _Alloc> bool std::operator<(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, const _CharT*)operator<(const basic_string<_CharT, _Traits, _Alloc>& __lhs,^~~~~~~~
/usr/include/c++/7/bits/basic_string.h:6107:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/string:52:0,from /usr/include/c++/7/bits/locale_classes.h:40,from /usr/include/c++/7/bits/ios_base.h:41,from /usr/include/c++/7/ios:42,from /usr/include/c++/7/ostream:38,from /usr/include/c++/7/iostream:39,from SRL_REQUIRES.cpp:9:
/usr/include/c++/7/bits/basic_string.h:6119:5: note: candidate: template<class _CharT, class _Traits, class _Alloc> bool std::operator<(const _CharT*, const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&)operator<(const _CharT* __lhs,^~~~~~~~
/usr/include/c++/7/bits/basic_string.h:6119:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: mismatched types ‘const _CharT*’ and ‘Base’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/bits/ios_base.h:46:0,from /usr/include/c++/7/ios:42,from /usr/include/c++/7/ostream:38,from /usr/include/c++/7/iostream:39,from SRL_REQUIRES.cpp:9:
/usr/include/c++/7/system_error:208:3: note: candidate: bool std::operator<(const std::error_code&, const std::error_code&)operator<(const error_code& __lhs, const error_code& __rhs) noexcept^~~~~~~~
/usr/include/c++/7/system_error:208:3: note: no known conversion for argument 1 from ‘Base’ to ‘const std::error_code&’
/usr/include/c++/7/system_error:282:3: note: candidate: bool std::operator<(const std::error_condition&, const std::error_condition&)operator<(const error_condition& __lhs,^~~~~~~~
/usr/include/c++/7/system_error:282:3: note: no known conversion for argument 1 from ‘Base’ to ‘const std::error_condition&’
In file included from /usr/include/c++/7/list:63:0,from SRL_REQUIRES.cpp:11:
/usr/include/c++/7/bits/stl_list.h:1918:5: note: candidate: template<class _Tp, class _Alloc> bool std::operator<(const std::__cxx11::list<_Tp, _Alloc>&, const std::__cxx11::list<_Tp, _Alloc>&)operator<(const list<_Tp, _Alloc>& __x, const list<_Tp, _Alloc>& __y)^~~~~~~~
/usr/include/c++/7/bits/stl_list.h:1918:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::__cxx11::list<_Tp, _Alloc>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/vector:64:0,from SRL_REQUIRES.cpp:12:
/usr/include/c++/7/bits/stl_vector.h:1618:5: note: candidate: template<class _Tp, class _Alloc> bool std::operator<(const std::vector<_Tp, _Alloc>&, const std::vector<_Tp, _Alloc>&)operator<(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y)^~~~~~~~
/usr/include/c++/7/bits/stl_vector.h:1618:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::vector<_Tp, _Alloc>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/deque:64:0,from /usr/include/c++/7/queue:60,from SRL_REQUIRES.cpp:13:
/usr/include/c++/7/bits/stl_deque.h:293:5: note: candidate: template<class _Tp, class _Ref, class _Ptr> bool std::operator<(const std::_Deque_iterator<_Tp, _Ref, _Ptr>&, const std::_Deque_iterator<_Tp, _Ref, _Ptr>&)operator<(const _Deque_iterator<_Tp, _Ref, _Ptr>& __x,^~~~~~~~
/usr/include/c++/7/bits/stl_deque.h:293:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::_Deque_iterator<_Tp, _Ref, _Ptr>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/deque:64:0,from /usr/include/c++/7/queue:60,from SRL_REQUIRES.cpp:13:
/usr/include/c++/7/bits/stl_deque.h:301:5: note: candidate: template<class _Tp, class _RefL, class _PtrL, class _RefR, class _PtrR> bool std::operator<(const std::_Deque_iterator<_Tp, _Ref, _Ptr>&, const std::_Deque_iterator<_Tp, _RefR, _PtrR>&)operator<(const _Deque_iterator<_Tp, _RefL, _PtrL>& __x,^~~~~~~~
/usr/include/c++/7/bits/stl_deque.h:301:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::_Deque_iterator<_Tp, _Ref, _Ptr>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/deque:64:0,from /usr/include/c++/7/queue:60,from SRL_REQUIRES.cpp:13:
/usr/include/c++/7/bits/stl_deque.h:2276:5: note: candidate: template<class _Tp, class _Alloc> bool std::operator<(const std::deque<_Tp, _Alloc>&, const std::deque<_Tp, _Alloc>&)operator<(const deque<_Tp, _Alloc>& __x,^~~~~~~~
/usr/include/c++/7/bits/stl_deque.h:2276:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::deque<_Tp, _Alloc>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/queue:64:0,from SRL_REQUIRES.cpp:13:
/usr/include/c++/7/bits/stl_queue.h:336:5: note: candidate: template<class _Tp, class _Seq> bool std::operator<(const std::queue<_Tp, _Seq>&, const std::queue<_Tp, _Seq>&)operator<(const queue<_Tp, _Seq>& __x, const queue<_Tp, _Seq>& __y)^~~~~~~~
/usr/include/c++/7/bits/stl_queue.h:336:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::queue<_Tp, _Seq>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/stack:61:0,from SRL_REQUIRES.cpp:14:
/usr/include/c++/7/bits/stl_stack.h:311:5: note: candidate: template<class _Tp, class _Seq> bool std::operator<(const std::stack<_Tp, _Seq>&, const std::stack<_Tp, _Seq>&)operator<(const stack<_Tp, _Seq>& __x, const stack<_Tp, _Seq>& __y)^~~~~~~~
/usr/include/c++/7/bits/stl_stack.h:311:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::stack<_Tp, _Seq>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/set:60:0,from SRL_REQUIRES.cpp:15:
/usr/include/c++/7/bits/stl_tree.h:1543:5: note: candidate: template<class _Key, class _Val, class _KeyOfValue, class _Compare, class _Alloc> bool std::operator<(const std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&, const std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&)operator<(const _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& __x,^~~~~~~~
/usr/include/c++/7/bits/stl_tree.h:1543:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/set:61:0,from SRL_REQUIRES.cpp:15:
/usr/include/c++/7/bits/stl_set.h:930:5: note: candidate: template<class _Key, class _Compare, class _Alloc> bool std::operator<(const std::set<_Key, _Compare, _Alloc>&, const std::set<_Key, _Compare, _Alloc>&)operator<(const set<_Key, _Compare, _Alloc>& __x,^~~~~~~~
/usr/include/c++/7/bits/stl_set.h:930:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::set<_Key, _Compare, _Alloc>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/set:62:0,from SRL_REQUIRES.cpp:15:
/usr/include/c++/7/bits/stl_multiset.h:913:5: note: candidate: template<class _Key, class _Compare, class _Alloc> bool std::operator<(const std::multiset<_Key, _Compare, _Alloc>&, const std::multiset<_Key, _Compare, _Alloc>&)operator<(const multiset<_Key, _Compare, _Alloc>& __x,^~~~~~~~
/usr/include/c++/7/bits/stl_multiset.h:913:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::multiset<_Key, _Compare, _Alloc>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/tuple:39:0,from /usr/include/c++/7/bits/stl_map.h:63,from /usr/include/c++/7/map:61,from SRL_REQUIRES.cpp:16:
/usr/include/c++/7/array:262:5: note: candidate: template<class _Tp, long unsigned int _Nm> bool std::operator<(const std::array<_Tp, _Nm>&, const std::array<_Tp, _Nm>&)operator<(const array<_Tp, _Nm>& __a, const array<_Tp, _Nm>& __b)^~~~~~~~
/usr/include/c++/7/array:262:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::array<_Tp, _Nm>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/bits/stl_map.h:63:0,from /usr/include/c++/7/map:61,from SRL_REQUIRES.cpp:16:
/usr/include/c++/7/tuple:1410:5: note: candidate: template<class ... _TElements, class ... _UElements> constexpr bool std::operator<(const std::tuple<_Tps ...>&, const std::tuple<_Args2 ...>&)operator<(const tuple<_TElements...>& __t,^~~~~~~~
/usr/include/c++/7/tuple:1410:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::tuple<_Tps ...>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/map:61:0,from SRL_REQUIRES.cpp:16:
/usr/include/c++/7/bits/stl_map.h:1411:5: note: candidate: template<class _Key, class _Tp, class _Compare, class _Alloc> bool std::operator<(const std::map<_Key, _Tp, _Compare, _Alloc>&, const std::map<_Key, _Tp, _Compare, _Alloc>&)operator<(const map<_Key, _Tp, _Compare, _Alloc>& __x,^~~~~~~~
/usr/include/c++/7/bits/stl_map.h:1411:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::map<_Key, _Tp, _Compare, _Alloc>’if (a < b) return a;~~^~~
In file included from /usr/include/c++/7/map:62:0,from SRL_REQUIRES.cpp:16:
/usr/include/c++/7/bits/stl_multimap.h:1076:5: note: candidate: template<class _Key, class _Tp, class _Compare, class _Alloc> bool std::operator<(const std::multimap<_Key, _Tp, _Compare, _Alloc>&, const std::multimap<_Key, _Tp, _Compare, _Alloc>&)operator<(const multimap<_Key, _Tp, _Compare, _Alloc>& __x,^~~~~~~~
/usr/include/c++/7/bits/stl_multimap.h:1076:5: note: template argument deduction/substitution failed:
SRL_REQUIRES.cpp:40:15: note: ‘Base’ is not derived from ‘const std::multimap<_Key, _Tp, _Compare, _Alloc>’if (a < b) return a;~~^~~
当我们重载小于号之后:
class Base {
public:bool operator<(Base &obj) const {return true;}
};
编译通过:
以上就是本文的全部内容!
:wq 拜拜~~