YSTest: cast.hpp 源文件

YSTest PreAlpha_b800_20170810 The YSLib Test Project

- 首页
- 相关页面
- 模块
- 命名空间
- 类
- 文件

- 文件列表
- 文件成员

cast.hpp
浏览该文件的文档.
1 /*
2 © 2010-2016 FrankHB.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
28 #ifndef YB_INC_ystdex_cast_hpp_
29 #define YB_INC_ystdex_cast_hpp_ 1
30
31 #include "type_op.hpp" // for decay_t, is_same,
32 // have_common_nonempty_virtual_base, false_, true_, _t;
33 #include <limits> // for std::numeric_limits;
34 #include "exception.h" // for narrowing_error, std::addressof;
35 #include <typeinfo> // for std::bad_cast;
36 #include "cassert.h" // for yassume;
37
39 namespace ystdex
40 {
41
53 template<typename _tSrc, typename _tDst = const decay_t<_tSrc>&&>
55 yconstfn _tDst
56 qualify(_tSrc&& arg) ynothrow
57 {
58 static_assert(is_same<decay_t<_tSrc>, decay_t<_tDst>>(),
59 "Non-qualification conversion found.");
60
61 return static_cast<_tDst>(arg);
62 }
63
64
66
67
69 template<typename _tDst, typename _tSrc>
70 using is_narrowing_from_floating_to_integer
71 = and_<is_integral<_tDst>, is_floating_point<_tSrc>>;
72
73 template<typename _tDst, typename _tSrc>
74 using is_narrowing_from_floating_to_floating
75 = and_<is_floating_point<_tDst>, is_floating_point<_tSrc>,
76 is_same<common_type_t<_tDst, _tSrc>, _tSrc>>;
77
78 template<typename _tDst, typename _tSrc>
79 using is_narrowing_from_floating
80 = or_<is_narrowing_from_floating_to_integer<_tDst, _tSrc>,
81 is_narrowing_from_floating_to_floating<_tDst, _tSrc>>;
83
84 namespace details
85 {
86
87 template<typename _tDst>
88 struct narrow_test
89 {
90 _tDst i;
91
93 yconstfn false_
94 get() const ynothrow
95 {
96 return {};
97 }
98 };
99
100 template<typename _tDst, typename _tSrc>
101 yconstfn auto
102 test_narrow(_tSrc v) ynothrow -> decltype(narrow_test<_tDst>{v}.get())
103 {
104 return narrow_test<_tDst>{v}.get();
105 }
107 template<typename>
108 yconstfn true_
109 test_narrow(...) ynothrow
110 {
111 return {};
112 }
113
114 } // namespace details;
116
118
119 template<typename _tDst, typename _tSrc>
121 yconstfn _tDst
122 narrow_cast(_tSrc v) ynothrow
123 {
124 static_assert(is_arithmetic<_tDst>(), "Invalid destination type found.");
125 static_assert(is_arithmetic<_tSrc>(), "Invalid source type found.");
126 static_assert(is_narrowing_from_floating<_tDst, _tSrc>()
127 || details::test_narrow<_tDst>(std::numeric_limits<_tSrc>::max())
128 || details::test_narrow<_tDst>(std::numeric_limits<_tSrc>::min()),
129 "Invalid types found.");
130
131 return static_cast<_tDst>(v);
132 }
133
135 template<typename _tDst, typename _tSrc>
136 inline _tDst
137 narrow(_tSrc v)
138 {
139 const auto d(narrow_cast<_tDst>(v));
140
141 if(static_cast<_tSrc>(d) == v && ((is_signed<_tDst>()
142 == is_signed<_tSrc>()) || (d < _tDst()) == (v < _tSrc())))
143 return d;
144 throw narrowing_error();
145 }
147
149
150 namespace details
151 {
152
153 template<typename _tDst, typename _tSrc>
154 yconstfn _tDst
155 not_widen_cast(_tSrc v, true_) ynothrow
156 {
157 return narrow_cast<_tDst>(v);
158 }
159 template<typename _tDst, typename _tSrc>
160 yconstfn _tDst
161 not_widen_cast(_tSrc v, false_) ynothrow
162 {
163 static_assert(is_arithmetic<_tDst>(), "Invalid destination type found.");
164 static_assert(is_arithmetic<_tSrc>(), "Invalid source type found.");
165 static_assert(std::numeric_limits<_tSrc>::max() == std::numeric_limits<
166 _tDst>::max() || std::numeric_limits<_tSrc>::min()
167 == std::numeric_limits<_tDst>::min(), "Invalid types found.");
168 return v;
169 }
170
171 } // namespace details;
172
177 template<typename _tDst, typename _tSrc>
178 yconstfn _tDst
179 not_widen_cast(_tSrc v) ynothrow
180 {
181 return details::not_widen_cast<_tDst>(v,
182 bool_<is_narrowing_from_floating<_tDst, _tSrc>()
183 || details::test_narrow<_tDst>(std::numeric_limits<_tSrc>::max())
184 || details::test_narrow<_tDst>(std::numeric_limits<_tSrc>::min())>());
185 }
186
188 template<typename _tDst, typename _tSrc>
189 inline _tDst
190 not_widen(_tSrc v)
191 {
192 const auto d(not_widen_cast<_tDst>(v));
193
194 if(static_cast<_tSrc>(d) == v && ((is_signed<_tDst>()
195 == is_signed<_tSrc>()) || (d < _tDst()) == (v < _tSrc())))
196 return d;
197 throw narrowing_error();
198 }
200
201
211 template<typename _pDst, class _tSrc>
212 inline _pDst
213 polymorphic_cast(_tSrc* v)
214 {
215 static_assert(is_polymorphic<_tSrc>(), "Non-polymorphic class found.");
216 static_assert(is_pointer<_pDst>(), "Non-pointer destination found.");
217
218 if(const auto p = dynamic_cast<_pDst>(v))
219 return p;
220 throw std::bad_cast();
221 }
222
236 template<typename _pDst, class _tSrc>
237 inline _pDst
238 polymorphic_downcast(_tSrc* v) ynothrowv
239 {
240 static_assert(is_polymorphic<_tSrc>(), "Non-polymorphic class found.");
241 static_assert(is_pointer<_pDst>(), "Non-pointer destination found.");
242 static_assert(is_base_of<_tSrc, remove_cv_t<
243 remove_pointer_t<_pDst>>>(), "Wrong destination type found.");
244
245 yassume(dynamic_cast<_pDst>(v) == v);
246 return static_cast<_pDst>(v);
247 }
253 template<typename _rDst, class _tSrc>
254 yconstfn yimpl(enable_if_t)<is_lvalue_reference<_rDst>::value, _rDst>
255 polymorphic_downcast(_tSrc& v) ynothrowv
256 {
257 return *ystdex::polymorphic_downcast<remove_reference_t<_rDst>*>(
258 std::addressof(v));
259 }
265 template<typename _rDst, class _tSrc>
266 yconstfn yimpl(enable_if_t)<is_rvalue_reference<_rDst>::value
267 && !is_reference<_tSrc>::value, _rDst>
268 polymorphic_downcast(_tSrc&& v) ynothrowv
269 {
270 return std::move(ystdex::polymorphic_downcast<_rDst&>(v));
271 }
280 template<class _tDst, typename _tSrc, typename _tDeleter>
281 inline yimpl(enable_if_t)<!is_reference<_tDst>::value
282 && !is_array<_tDst>::value, std::unique_ptr<_tDst, _tDeleter>>
283 polymorphic_downcast(std::unique_ptr<_tSrc, _tDeleter>&& v) ynothrowv
284 {
285 using dst_type = std::unique_ptr<_tDst, _tDeleter>;
286 using pointer = typename dst_type::pointer;
287 auto ptr(v.release());
288 ynoexcept_assert("Invalid cast found.", polymorphic_downcast<pointer>(ptr));
289
290 yassume(bool(ptr));
291 return dst_type(polymorphic_downcast<pointer>(ptr),
292 std::move(v.get_deleter()));
293 }
299 template<class _tDst, typename _tSrc>
300 inline yimpl(enable_if_t)<!is_reference<_tDst>::value
301 && !is_array<_tDst>::value, std::shared_ptr<_tDst>>
302 polymorphic_downcast(const std::unique_ptr<_tSrc>& v) ynothrowv
303 {
304 yassume(dynamic_cast<_tDst*>(v.get()) == v.get());
305
306 return std::static_pointer_cast<_tDst>(v);
307 }
309
311
312
322 template<typename _pDst, class _tSrc>
323 inline _pDst
324 polymorphic_crosscast(_tSrc* v)
325 {
326 static_assert(is_polymorphic<_tSrc>(), "Non-polymorphic class found.");
327 static_assert(is_pointer<_pDst>(), "Non-pointer destination found.");
328
329 auto p(dynamic_cast<_pDst>(v));
330
331 yassume(p);
332 return p;
333 }
340 template<typename _rDst, class _tSrc>
341 yconstfn _rDst
342 polymorphic_crosscast(_tSrc& v)
343 {
344 static_assert(is_lvalue_reference<_rDst>(),
345 "Invalid destination type found.");
346
347 return *ystdex::polymorphic_crosscast<remove_reference_t<_rDst>*>(
348 std::addressof(v));
349 }
356 template<typename _rDst, class _tSrc>
357 yconstfn enable_if_t<!is_reference<_tSrc>::value, _rDst>
358 polymorphic_crosscast(_tSrc&& v)
359 {
360 static_assert(is_rvalue_reference<_rDst>(),
361 "Invalid destination type found.");
362
363 return std::move(ystdex::polymorphic_crosscast<_rDst&>(v));
364 }
366
367
368 namespace details
369 {
370
372
373 template<typename _tFrom, typename _tTo, bool _bNonVirtualDownCast>
374 struct general_polymorphic_cast_helper
375 {
376 static yconstfn _tTo
377 cast(_tFrom v)
378 {
379 return ystdex::polymorphic_downcast<_tTo>(v);
380 }
381 };
382
383 template<typename _tFrom, typename _tTo>
384 struct general_polymorphic_cast_helper<_tFrom, _tTo, false>
385 {
386 static yconstfn _tTo
387 cast(_tFrom v)
388 {
389 return dynamic_cast<_tTo>(v);
390 }
391 };
392
393
394 template<typename _tFrom, typename _tTo, bool _bUseStaticCast>
395 struct general_cast_helper
396 {
397 static yconstfn _tTo
398 cast(_tFrom v)
399 {
400 return _tTo(v);
401 }
402 };
403
404 template<typename _tFrom, typename _tTo>
405 struct general_cast_helper<_tFrom, _tTo, false>
406 {
407 static yconstfn _tTo
408 cast(_tFrom v)
409 {
410 return general_polymorphic_cast_helper<_tFrom, _tTo, and_<is_base_of<
411 _tFrom, _tTo>, not_<have_common_nonempty_virtual_base<
412 _t<remove_rp<_tFrom>>, _t<remove_rp<_tTo>>>>>::value>::cast(v);
413 }
414 };
415
416 template<typename _type>
417 struct general_cast_helper<_type, _type, true>
418 {
419 static _type
420 cast(_type v)
421 {
422 return v;
423 }
424 };
425
426 template<typename _type>
427 struct general_cast_helper<_type, _type, false>
428 {
429 static yconstfn _type
430 cast(_type v)
431 {
432 return v;
433 }
434 };
435
436 template<typename _tFrom, typename _tTo>
437 struct general_cast_type_helper : is_convertible<_tFrom, _tTo>
438 {};
440
441 } // namespace details;
442
455 template<typename _tDst, typename _tSrc>
456 yconstfn _tDst
457 general_cast(_tSrc* v)
458 {
459 return details::general_cast_helper<_tSrc*, _tDst,
460 details::general_cast_type_helper<_tSrc*, _tDst>::value>::cast(v);
461 }
462 template<typename _tDst, typename _tSrc>
463 yconstfn _tDst
464 general_cast(_tSrc& v)
465 {
466 return details::general_cast_helper<_tSrc&, _tDst,
467 details::general_cast_type_helper<_tSrc&, _tDst>::value>::cast(v);
468 }
469 template<typename _tDst, typename _tSrc>
470 yconstfn const _tDst
471 general_cast(const _tSrc& v)
472 {
473 return details::general_cast_helper<const _tSrc&, _tDst, details
474 ::general_cast_type_helper<const _tSrc&, const _tDst>::value>::cast(v);
475 }
477
478
479 } // namespace ystdex;
480
481 #endif
482
ystdex::details::have_common_nonempty_virtual_base
Definition: type_op.hpp:112
ystdex::details::general_cast_helper::cast
static _tTo cast(_tFrom v)
Definition: cast.hpp:398
ystdex::details::general_cast_helper
Definition: cast.hpp:395
ystdex::true_
bool_< true > true_
Definition: type_traits.hpp:391
ystdex::polymorphic_cast
_pDst polymorphic_cast(_tSrc *v)
多态类指针类型转换。
Definition: cast.hpp:213
yconstfn
#define yconstfn
指定编译时常量函数。
Definition: ydef.h:680
v
byte v
Definition: CharRenderer.cpp:75
ystdex::details::test_narrow
auto test_narrow(_tSrc v) -> decltype(narrow_test< _tDst >
Definition: cast.hpp:102
ystdex::cpp2014::remove_cv_t
typename remove_cv< _type >::type remove_cv_t
Definition: type_traits.hpp:286
ystdex::details::general_cast_helper< _type, _type, true >::cast
static _type cast(_type v)
Definition: cast.hpp:420
ystdex::narrow
_tDst narrow(_tSrc v)
Definition: cast.hpp:137
ystdex::false_
bool_< false > false_
Definition: type_traits.hpp:392
ystdex::not_
Definition: type_traits.hpp:456
ynoexcept_assert
#define ynoexcept_assert(_msg,...)
表达式 noexcept 静态断言。
Definition: ydef.h:747
ystdex::or_
Definition: type_traits.hpp:438
yimpl
#define yimpl(...)
实现标签。
Definition: ydef.h:262
ystdex::details::general_polymorphic_cast_helper::cast
static _tTo cast(_tFrom v)
Definition: cast.hpp:377
ystdex::cpp2014::enable_if_t
typename enable_if< _bCond, _type >::type enable_if_t
Definition: type_traits.hpp:343
ystdex::polymorphic_downcast
_pDst polymorphic_downcast(_tSrc *v)
多态类指针向派生类指针转换。
Definition: cast.hpp:238
ystdex::details::narrow_test
Definition: cast.hpp:88
ystdex::max
const _type & max(const _type &a, const _type &b, _fComp comp=less< _type >())
取较大的元素。
Definition: algorithm.hpp:549
ystdex::details::general_cast_helper< _tFrom, _tTo, false >::cast
static _tTo cast(_tFrom v)
Definition: cast.hpp:408
ystdex::not_widen
_tDst not_widen(_tSrc v)
Definition: cast.hpp:190
ystdex::is_narrowing_from_floating_to_integer
and_< is_integral< _tDst >, is_floating_point< _tSrc >> is_narrowing_from_floating_to_integer
Definition: cast.hpp:71
ystdex::not_widen_cast
_tDst not_widen_cast(_tSrc v)
可能缩小数值范围或数值范围最大和最小值保持不变的转换。
Definition: cast.hpp:179
ynothrow
#define ynothrow
YSLib 无异常抛出保证：若支持 noexcept 关键字， 指定特定的 noexcept 异常规范。
Definition: ydef.h:766
ystdex
特性测试宏。
Definition: ydef.h:822
ystdex::narrow_cast
_tDst narrow_cast(_tSrc v)
可能缩小数值范围的显式转换。
Definition: cast.hpp:122
ystdex::min
const _type & min(const _type &a, const _type &b, _fComp comp=less< _type >())
取较小的元素。
Definition: algorithm.hpp:527
type_op.hpp
C++ 类型操作。
cassert.h
ISO C 断言/调试跟踪扩展。
ystdex::_t
typename _type::type _t
嵌套类型别名。
Definition: type_traits.hpp:97
ystdex::static_pointer_cast
std::unique_ptr< _tDst > static_pointer_cast(std::unique_ptr< _type > p)
智能指针转换。
Definition: memory.hpp:1007
exception.h
ystdex::details::general_cast_type_helper
Definition: cast.hpp:437
ynothrowv
#define ynothrowv
YSLib 无异常抛出保证验证：有条件地使用无异常抛出规范。
Definition: ydef.h:786
ystdex::narrowing_error
异常：无法表示数值范围的转换。
Definition: ystdex/exception.h:157
ystdex::details::narrow_test::i
_tDst i
Definition: cast.hpp:90
ystdex::details::general_cast_helper< _type, _type, false >::cast
static _type cast(_type v)
Definition: cast.hpp:430
ystdex::details::not_widen_cast
_tDst not_widen_cast(_tSrc v, true_)
Definition: cast.hpp:155
ystdex::details::general_polymorphic_cast_helper< _tFrom, _tTo, false >::cast
static _tTo cast(_tFrom v)
Definition: cast.hpp:387
yassume
#define yassume(_expr)
假定：环境语义。
Definition: cassert.h:105
ystdex::polymorphic_crosscast
_pDst polymorphic_crosscast(_tSrc *v)
多态类指针交叉转换。
Definition: cast.hpp:324
ystdex::general_cast
_tDst general_cast(_tSrc *v)
一般类型转换。
Definition: cast.hpp:457
CHRLib::d
_tDst * d
Definition: CharacterProcessing.h:139
ystdex::and_
逻辑操作元函数。
Definition: type_traits.hpp:420
ystdex::qualify
_tDst qualify(_tSrc &&arg)
允许添加限定符转换。
Definition: cast.hpp:56
ystdex::bool_
std::integral_constant< bool, _vInt > bool_
Definition: type_traits.hpp:375
CHRLib::p
const auto p(d)
ystdex::details::general_polymorphic_cast_helper
Definition: cast.hpp:374