variant.hpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html.
  4. //
  5. // Copyright (C) 2018 Intel Corporation
  6. #ifndef OPENCV_GAPI_UTIL_VARIANT_HPP
  7. #define OPENCV_GAPI_UTIL_VARIANT_HPP
  8. #include <array>
  9. #include <type_traits>
  10. #include <opencv2/gapi/util/compiler_hints.hpp>
  11. #include <opencv2/gapi/util/throw.hpp>
  12. #include <opencv2/gapi/util/util.hpp> // max_of_t
  13. #include <opencv2/gapi/util/type_traits.hpp>
  14. // A poor man's `variant` implementation, incompletely modeled against C++17 spec.
  15. namespace cv
  16. {
  17. namespace util
  18. {
  19. namespace detail
  20. {
  21. template<std::size_t I, typename Target, typename First, typename... Remaining>
  22. struct type_list_index_helper
  23. {
  24. static const constexpr bool is_same = std::is_same<Target, First>::value;
  25. static const constexpr std::size_t value =
  26. std::conditional<is_same, std::integral_constant<std::size_t, I>, type_list_index_helper<I + 1, Target, Remaining...>>::type::value;
  27. };
  28. template<std::size_t I, typename Target, typename First>
  29. struct type_list_index_helper<I, Target, First>
  30. {
  31. static_assert(std::is_same<Target, First>::value, "Type not found");
  32. static const constexpr std::size_t value = I;
  33. };
  34. }
  35. template<typename Target, typename... Types>
  36. struct type_list_index
  37. {
  38. static const constexpr std::size_t value = detail::type_list_index_helper<0, Target, Types...>::value;
  39. };
  40. template<std::size_t Index, class... Types >
  41. struct type_list_element
  42. {
  43. using type = typename std::tuple_element<Index, std::tuple<Types...> >::type;
  44. };
  45. class bad_variant_access: public std::exception
  46. {
  47. public:
  48. virtual const char *what() const noexcept override
  49. {
  50. return "Bad variant access";
  51. }
  52. };
  53. // Interface ///////////////////////////////////////////////////////////////
  54. struct monostate {};
  55. inline bool operator==(const util::monostate&, const util::monostate&)
  56. {
  57. return true;
  58. }
  59. template<typename... Ts> // FIXME: no references, arrays, and void
  60. class variant
  61. {
  62. // FIXME: Replace with std::aligned_union after gcc4.8 support is dropped
  63. static constexpr const std::size_t S = cv::detail::max_of_t<sizeof(Ts)...>::value;
  64. static constexpr const std::size_t A = cv::detail::max_of_t<alignof(Ts)...>::value;
  65. using Memory = typename std::aligned_storage<S, A>::type[1];
  66. template<typename T> struct cctr_h {
  67. static void help(Memory memory, const Memory from) {
  68. new (memory) T(*reinterpret_cast<const T*>(from));
  69. }
  70. };
  71. template<typename T> struct mctr_h {
  72. static void help(Memory memory, void *pval) {
  73. new (memory) T(std::move(*reinterpret_cast<T*>(pval)));
  74. }
  75. };
  76. //FIXME: unify with cctr_h and mctr_h
  77. template<typename T> struct cnvrt_ctor_h {
  78. static void help(Memory memory, void* from) {
  79. using util::decay_t;
  80. new (memory) decay_t<T>(std::forward<T>(*reinterpret_cast<decay_t<T>*>(from)));
  81. }
  82. };
  83. template<typename T> struct copy_h {
  84. static void help(Memory to, const Memory from) {
  85. *reinterpret_cast<T*>(to) = *reinterpret_cast<const T*>(from);
  86. }
  87. };
  88. template<typename T> struct move_h {
  89. static void help(Memory to, Memory from) {
  90. *reinterpret_cast<T*>(to) = std::move(*reinterpret_cast<T*>(from));
  91. }
  92. };
  93. //FIXME: unify with copy_h and move_h
  94. template<typename T> struct cnvrt_assign_h {
  95. static void help(Memory to, void* from) {
  96. using util::decay_t;
  97. *reinterpret_cast<decay_t<T>*>(to) = std::forward<T>(*reinterpret_cast<decay_t<T>*>(from));
  98. }
  99. };
  100. template<typename T> struct swap_h {
  101. static void help(Memory to, Memory from) {
  102. std::swap(*reinterpret_cast<T*>(to), *reinterpret_cast<T*>(from));
  103. }
  104. };
  105. template<typename T> struct dtor_h {
  106. static void help(Memory memory) {
  107. (void) memory; // MSCV warning
  108. reinterpret_cast<T*>(memory)->~T();
  109. }
  110. };
  111. template<typename T> struct equal_h {
  112. static bool help(const Memory lhs, const Memory rhs) {
  113. const T& t_lhs = *reinterpret_cast<const T*>(lhs);
  114. const T& t_rhs = *reinterpret_cast<const T*>(rhs);
  115. return t_lhs == t_rhs;
  116. }
  117. };
  118. typedef void (*CCtr) (Memory, const Memory); // Copy c-tor (variant)
  119. typedef void (*MCtr) (Memory, void*); // Generic move c-tor
  120. typedef void (*Copy) (Memory, const Memory); // Copy assignment
  121. typedef void (*Move) (Memory, Memory); // Move assignment
  122. typedef void (*Swap) (Memory, Memory); // Swap
  123. typedef void (*Dtor) (Memory); // Destructor
  124. using cnvrt_assgn_t = void (*) (Memory, void*); // Converting assignment (via std::forward)
  125. using cnvrt_ctor_t = void (*) (Memory, void*); // Converting constructor (via std::forward)
  126. typedef bool (*Equal)(const Memory, const Memory); // Equality test (external)
  127. static constexpr std::array<CCtr, sizeof...(Ts)> cctrs(){ return {{(&cctr_h<Ts>::help)...}};}
  128. static constexpr std::array<MCtr, sizeof...(Ts)> mctrs(){ return {{(&mctr_h<Ts>::help)...}};}
  129. static constexpr std::array<Copy, sizeof...(Ts)> cpyrs(){ return {{(&copy_h<Ts>::help)...}};}
  130. static constexpr std::array<Move, sizeof...(Ts)> mvers(){ return {{(&move_h<Ts>::help)...}};}
  131. static constexpr std::array<Swap, sizeof...(Ts)> swprs(){ return {{(&swap_h<Ts>::help)...}};}
  132. static constexpr std::array<Dtor, sizeof...(Ts)> dtors(){ return {{(&dtor_h<Ts>::help)...}};}
  133. template<bool cond, typename T>
  134. struct conditional_ref : std::conditional<cond, typename std::remove_reference<T>::type&, typename std::remove_reference<T>::type > {};
  135. template<bool cond, typename T>
  136. using conditional_ref_t = typename conditional_ref<cond, T>::type;
  137. template<bool is_lvalue_arg>
  138. static constexpr std::array<cnvrt_assgn_t, sizeof...(Ts)> cnvrt_assgnrs(){
  139. return {{(&cnvrt_assign_h<conditional_ref_t<is_lvalue_arg,Ts>>::help)...}};
  140. }
  141. template<bool is_lvalue_arg>
  142. static constexpr std::array<cnvrt_ctor_t, sizeof...(Ts)> cnvrt_ctors(){
  143. return {{(&cnvrt_ctor_h<conditional_ref_t<is_lvalue_arg,Ts>>::help)...}};
  144. }
  145. std::size_t m_index = 0;
  146. protected:
  147. template<typename T, typename... Us> friend T& get(variant<Us...> &v);
  148. template<typename T, typename... Us> friend const T& get(const variant<Us...> &v);
  149. template<typename T, typename... Us> friend T* get_if(variant<Us...> *v) noexcept;
  150. template<typename T, typename... Us> friend const T* get_if(const variant<Us...> *v) noexcept;
  151. template<typename... Us> friend bool operator==(const variant<Us...> &lhs,
  152. const variant<Us...> &rhs);
  153. Memory memory;
  154. public:
  155. // Constructors
  156. variant() noexcept;
  157. variant(const variant& other);
  158. variant(variant&& other) noexcept;
  159. // are_different_t is a SFINAE trick to avoid variant(T &&t) with T=variant
  160. // for some reason, this version is called instead of variant(variant&& o) when
  161. // variant is used in STL containers (examples: vector assignment).
  162. template<
  163. typename T,
  164. typename = util::are_different_t<variant, T>
  165. >
  166. explicit variant(T&& t);
  167. // template<class T, class... Args> explicit variant(Args&&... args);
  168. // FIXME: other constructors
  169. // Destructor
  170. ~variant();
  171. // Assignment
  172. variant& operator=(const variant& rhs);
  173. variant& operator=(variant &&rhs) noexcept;
  174. // SFINAE trick to avoid operator=(T&&) with T=variant<>, see comment above
  175. template<
  176. typename T,
  177. typename = util::are_different_t<variant, T>
  178. >
  179. variant& operator=(T&& t) noexcept;
  180. // Observers
  181. std::size_t index() const noexcept;
  182. // FIXME: valueless_by_exception()
  183. // Modifiers
  184. // FIXME: emplace()
  185. void swap(variant &rhs) noexcept;
  186. // Non-C++17x!
  187. template<typename T> static constexpr std::size_t index_of();
  188. };
  189. // FIMXE: visit
  190. template<typename T, typename... Types>
  191. T* get_if(util::variant<Types...>* v) noexcept;
  192. template<typename T, typename... Types>
  193. const T* get_if(const util::variant<Types...>* v) noexcept;
  194. template<typename T, typename... Types>
  195. T& get(util::variant<Types...> &v);
  196. template<typename T, typename... Types>
  197. const T& get(const util::variant<Types...> &v);
  198. template<std::size_t Index, typename... Types>
  199. typename util::type_list_element<Index, Types...>::type& get(util::variant<Types...> &v);
  200. template<std::size_t Index, typename... Types>
  201. const typename util::type_list_element<Index, Types...>::type& get(const util::variant<Types...> &v);
  202. template<typename T, typename... Types>
  203. bool holds_alternative(const util::variant<Types...> &v) noexcept;
  204. // Visitor
  205. namespace detail
  206. {
  207. struct visitor_interface {};
  208. // Class `visitor_return_type_deduction_helper`
  209. // introduces solution for deduction `return_type` in `visit` function in common way
  210. // for both Lambda and class Visitor and keep one interface invocation point: `visit` only
  211. // his helper class is required to unify return_type deduction mechanism because
  212. // for Lambda it is possible to take type of `decltype(visitor(get<0>(var)))`
  213. // but for class Visitor there is no operator() in base case,
  214. // because it provides `operator() (std::size_t index, ...)`
  215. // So `visitor_return_type_deduction_helper` expose `operator()`
  216. // uses only for class Visitor only for deduction `return type` in visit()
  217. template<typename R>
  218. struct visitor_return_type_deduction_helper
  219. {
  220. using return_type = R;
  221. // to be used in Lambda return type deduction context only
  222. template<typename T>
  223. return_type operator() (T&&);
  224. };
  225. }
  226. // Special purpose `static_visitor` can receive additional arguments
  227. template<typename R, typename Impl>
  228. struct static_visitor : public detail::visitor_interface,
  229. public detail::visitor_return_type_deduction_helper<R> {
  230. // assign responsibility for return type deduction to helper class
  231. using return_type = typename detail::visitor_return_type_deduction_helper<R>::return_type;
  232. using detail::visitor_return_type_deduction_helper<R>::operator();
  233. friend Impl;
  234. template<typename VariantValue, typename ...Args>
  235. return_type operator() (std::size_t index, VariantValue&& value, Args&& ...args)
  236. {
  237. suppress_unused_warning(index);
  238. return static_cast<Impl*>(this)-> visit(
  239. std::forward<VariantValue>(value),
  240. std::forward<Args>(args)...);
  241. }
  242. };
  243. // Special purpose `static_indexed_visitor` can receive additional arguments
  244. // And make forwarding current variant index as runtime function argument to its `Impl`
  245. template<typename R, typename Impl>
  246. struct static_indexed_visitor : public detail::visitor_interface,
  247. public detail::visitor_return_type_deduction_helper<R> {
  248. // assign responsibility for return type deduction to helper class
  249. using return_type = typename detail::visitor_return_type_deduction_helper<R>::return_type;
  250. using detail::visitor_return_type_deduction_helper<R>::operator();
  251. friend Impl;
  252. template<typename VariantValue, typename ...Args>
  253. return_type operator() (std::size_t Index, VariantValue&& value, Args&& ...args)
  254. {
  255. return static_cast<Impl*>(this)-> visit(Index,
  256. std::forward<VariantValue>(value),
  257. std::forward<Args>(args)...);
  258. }
  259. };
  260. template <class T>
  261. struct variant_size;
  262. template <class... Types>
  263. struct variant_size<util::variant<Types...>>
  264. : std::integral_constant<std::size_t, sizeof...(Types)> { };
  265. // FIXME: T&&, const TT&& versions.
  266. // Implementation //////////////////////////////////////////////////////////
  267. template<typename... Ts>
  268. variant<Ts...>::variant() noexcept
  269. {
  270. typedef typename std::tuple_element<0, std::tuple<Ts...> >::type TFirst;
  271. new (memory) TFirst();
  272. }
  273. template<typename... Ts>
  274. variant<Ts...>::variant(const variant &other)
  275. : m_index(other.m_index)
  276. {
  277. (cctrs()[m_index])(memory, other.memory);
  278. }
  279. template<typename... Ts>
  280. variant<Ts...>::variant(variant &&other) noexcept
  281. : m_index(other.m_index)
  282. {
  283. (mctrs()[m_index])(memory, other.memory);
  284. }
  285. template<typename... Ts>
  286. template<class T, typename>
  287. variant<Ts...>::variant(T&& t)
  288. : m_index(util::type_list_index<util::decay_t<T>, Ts...>::value)
  289. {
  290. const constexpr bool is_lvalue_arg = std::is_lvalue_reference<T>::value;
  291. (cnvrt_ctors<is_lvalue_arg>()[m_index])(memory, const_cast<util::decay_t<T> *>(&t));
  292. }
  293. template<typename... Ts>
  294. variant<Ts...>::~variant()
  295. {
  296. (dtors()[m_index])(memory);
  297. }
  298. template<typename... Ts>
  299. variant<Ts...>& variant<Ts...>::operator=(const variant<Ts...> &rhs)
  300. {
  301. if (m_index != rhs.m_index)
  302. {
  303. (dtors()[ m_index])(memory);
  304. (cctrs()[rhs.m_index])(memory, rhs.memory);
  305. m_index = rhs.m_index;
  306. }
  307. else
  308. {
  309. (cpyrs()[rhs.m_index])(memory, rhs.memory);
  310. }
  311. return *this;
  312. }
  313. template<typename... Ts>
  314. variant<Ts...>& variant<Ts...>::operator=(variant<Ts...> &&rhs) noexcept
  315. {
  316. if (m_index != rhs.m_index)
  317. {
  318. (dtors()[ m_index])(memory);
  319. (mctrs()[rhs.m_index])(memory, rhs.memory);
  320. m_index = rhs.m_index;
  321. }
  322. else
  323. {
  324. (mvers()[rhs.m_index])(memory, rhs.memory);
  325. }
  326. return *this;
  327. }
  328. template<typename... Ts>
  329. template<typename T, typename>
  330. variant<Ts...>& variant<Ts...>::operator=(T&& t) noexcept
  331. {
  332. using decayed_t = util::decay_t<T>;
  333. // FIXME: No version with implicit type conversion available!
  334. const constexpr std::size_t t_index =
  335. util::type_list_index<decayed_t, Ts...>::value;
  336. const constexpr bool is_lvalue_arg = std::is_lvalue_reference<T>::value;
  337. if (t_index != m_index)
  338. {
  339. (dtors()[m_index])(memory);
  340. (cnvrt_ctors<is_lvalue_arg>()[t_index])(memory, &t);
  341. m_index = t_index;
  342. }
  343. else
  344. {
  345. (cnvrt_assgnrs<is_lvalue_arg>()[m_index])(memory, &t);
  346. }
  347. return *this;
  348. }
  349. template<typename... Ts>
  350. std::size_t util::variant<Ts...>::index() const noexcept
  351. {
  352. return m_index;
  353. }
  354. template<typename... Ts>
  355. void variant<Ts...>::swap(variant<Ts...> &rhs) noexcept
  356. {
  357. if (m_index == rhs.index())
  358. {
  359. (swprs()[m_index](memory, rhs.memory));
  360. }
  361. else
  362. {
  363. variant<Ts...> tmp(std::move(*this));
  364. *this = std::move(rhs);
  365. rhs = std::move(tmp);
  366. }
  367. }
  368. template<typename... Ts>
  369. template<typename T>
  370. constexpr std::size_t variant<Ts...>::index_of()
  371. {
  372. return util::type_list_index<T, Ts...>::value; // FIXME: tests!
  373. }
  374. template<typename T, typename... Types>
  375. T* get_if(util::variant<Types...>* v) noexcept
  376. {
  377. const constexpr std::size_t t_index =
  378. util::type_list_index<T, Types...>::value;
  379. if (v && v->index() == t_index)
  380. return (T*)(&v->memory); // workaround for ICC 2019
  381. // original code: return reinterpret_cast<T&>(v.memory);
  382. return nullptr;
  383. }
  384. template<typename T, typename... Types>
  385. const T* get_if(const util::variant<Types...>* v) noexcept
  386. {
  387. const constexpr std::size_t t_index =
  388. util::type_list_index<T, Types...>::value;
  389. if (v && v->index() == t_index)
  390. return (const T*)(&v->memory); // workaround for ICC 2019
  391. // original code: return reinterpret_cast<const T&>(v.memory);
  392. return nullptr;
  393. }
  394. template<typename T, typename... Types>
  395. T& get(util::variant<Types...> &v)
  396. {
  397. if (auto* p = get_if<T>(&v))
  398. return *p;
  399. else
  400. throw_error(bad_variant_access());
  401. }
  402. template<typename T, typename... Types>
  403. const T& get(const util::variant<Types...> &v)
  404. {
  405. if (auto* p = get_if<T>(&v))
  406. return *p;
  407. else
  408. throw_error(bad_variant_access());
  409. }
  410. template<std::size_t Index, typename... Types>
  411. typename util::type_list_element<Index, Types...>::type& get(util::variant<Types...> &v)
  412. {
  413. using ReturnType = typename util::type_list_element<Index, Types...>::type;
  414. return const_cast<ReturnType&>(get<Index, Types...>(static_cast<const util::variant<Types...> &>(v)));
  415. }
  416. template<std::size_t Index, typename... Types>
  417. const typename util::type_list_element<Index, Types...>::type& get(const util::variant<Types...> &v)
  418. {
  419. static_assert(Index < sizeof...(Types),
  420. "`Index` it out of bound of `util::variant` type list");
  421. using ReturnType = typename util::type_list_element<Index, Types...>::type;
  422. return get<ReturnType>(v);
  423. }
  424. template<typename T, typename... Types>
  425. bool holds_alternative(const util::variant<Types...> &v) noexcept
  426. {
  427. return v.index() == util::variant<Types...>::template index_of<T>();
  428. }
  429. template<typename... Us> bool operator==(const variant<Us...> &lhs,
  430. const variant<Us...> &rhs)
  431. {
  432. using V = variant<Us...>;
  433. // Instantiate table only here since it requires operator== for <Us...>
  434. // <Us...> should have operator== only if this one is used, not in general
  435. static const std::array<typename V::Equal, sizeof...(Us)> eqs = {
  436. {(&V::template equal_h<Us>::help)...}
  437. };
  438. if (lhs.index() != rhs.index())
  439. return false;
  440. return (eqs[lhs.index()])(lhs.memory, rhs.memory);
  441. }
  442. template<typename... Us> bool operator!=(const variant<Us...> &lhs,
  443. const variant<Us...> &rhs)
  444. {
  445. return !(lhs == rhs);
  446. }
  447. namespace detail
  448. {
  449. // terminate recursion implementation for `non-void` ReturnType
  450. template<typename ReturnType, std::size_t CurIndex, std::size_t ElemCount,
  451. typename Visitor, typename Variant, typename... VisitorArgs>
  452. ReturnType apply_visitor_impl(Visitor&&, Variant&,
  453. std::true_type, std::false_type,
  454. VisitorArgs&& ...)
  455. {
  456. return {};
  457. }
  458. // terminate recursion implementation for `void` ReturnType
  459. template<typename ReturnType, std::size_t CurIndex, std::size_t ElemCount,
  460. typename Visitor, typename Variant, typename... VisitorArgs>
  461. void apply_visitor_impl(Visitor&&, Variant&,
  462. std::true_type, std::true_type,
  463. VisitorArgs&& ...)
  464. {
  465. }
  466. // Intermediate resursion processor for Lambda Visitors
  467. template<typename ReturnType, std::size_t CurIndex, std::size_t ElemCount,
  468. typename Visitor, typename Variant, bool no_return_value, typename... VisitorArgs>
  469. typename std::enable_if<!std::is_base_of<visitor_interface, typename std::decay<Visitor>::type>::value, ReturnType>::type
  470. apply_visitor_impl(Visitor&& visitor, Variant&& v, std::false_type not_processed,
  471. std::integral_constant<bool, no_return_value> should_no_return,
  472. VisitorArgs&& ...args)
  473. {
  474. static_assert(std::is_same<ReturnType, decltype(visitor(get<CurIndex>(v)))>::value,
  475. "Different `ReturnType`s detected! All `Visitor::visit` or `overload_lamba_set`"
  476. " must return the same type");
  477. suppress_unused_warning(not_processed);
  478. if (v.index() == CurIndex)
  479. {
  480. return visitor.operator()(get<CurIndex>(v), std::forward<VisitorArgs>(args)... );
  481. }
  482. using is_variant_processed_t = std::integral_constant<bool, CurIndex + 1 >= ElemCount>;
  483. return apply_visitor_impl<ReturnType, CurIndex +1, ElemCount>(
  484. std::forward<Visitor>(visitor),
  485. std::forward<Variant>(v),
  486. is_variant_processed_t{},
  487. should_no_return,
  488. std::forward<VisitorArgs>(args)...);
  489. }
  490. //Visual Studio 2014 compilation fix: cast visitor to base class before invoke operator()
  491. template<std::size_t CurIndex, typename ReturnType, typename Visitor, class Value, typename... VisitorArgs>
  492. typename std::enable_if<std::is_base_of<static_visitor<ReturnType, typename std::decay<Visitor>::type>,
  493. typename std::decay<Visitor>::type>::value, ReturnType>::type
  494. invoke_class_visitor(Visitor& visitor, Value&& v, VisitorArgs&&...args)
  495. {
  496. return static_cast<static_visitor<ReturnType, typename std::decay<Visitor>::type>&>(visitor).operator() (CurIndex, std::forward<Value>(v), std::forward<VisitorArgs>(args)... );
  497. }
  498. //Visual Studio 2014 compilation fix: cast visitor to base class before invoke operator()
  499. template<std::size_t CurIndex, typename ReturnType, typename Visitor, class Value, typename... VisitorArgs>
  500. typename std::enable_if<std::is_base_of<static_indexed_visitor<ReturnType, typename std::decay<Visitor>::type>,
  501. typename std::decay<Visitor>::type>::value, ReturnType>::type
  502. invoke_class_visitor(Visitor& visitor, Value&& v, VisitorArgs&&...args)
  503. {
  504. return static_cast<static_indexed_visitor<ReturnType, typename std::decay<Visitor>::type>&>(visitor).operator() (CurIndex, std::forward<Value>(v), std::forward<VisitorArgs>(args)... );
  505. }
  506. // Intermediate recursion processor for special case `visitor_interface` derived Visitors
  507. template<typename ReturnType, std::size_t CurIndex, std::size_t ElemCount,
  508. typename Visitor, typename Variant, bool no_return_value, typename... VisitorArgs>
  509. typename std::enable_if<std::is_base_of<visitor_interface, typename std::decay<Visitor>::type>::value, ReturnType>::type
  510. apply_visitor_impl(Visitor&& visitor, Variant&& v, std::false_type not_processed,
  511. std::integral_constant<bool, no_return_value> should_no_return,
  512. VisitorArgs&& ...args)
  513. {
  514. static_assert(std::is_same<ReturnType, decltype(visitor(get<CurIndex>(v)))>::value,
  515. "Different `ReturnType`s detected! All `Visitor::visit` or `overload_lamba_set`"
  516. " must return the same type");
  517. suppress_unused_warning(not_processed);
  518. if (v.index() == CurIndex)
  519. {
  520. return invoke_class_visitor<CurIndex, ReturnType>(visitor, get<CurIndex>(v), std::forward<VisitorArgs>(args)... );
  521. }
  522. using is_variant_processed_t = std::integral_constant<bool, CurIndex + 1 >= ElemCount>;
  523. return apply_visitor_impl<ReturnType, CurIndex +1, ElemCount>(
  524. std::forward<Visitor>(visitor),
  525. std::forward<Variant>(v),
  526. is_variant_processed_t{},
  527. should_no_return,
  528. std::forward<VisitorArgs>(args)...);
  529. }
  530. } // namespace detail
  531. template<typename Visitor, typename Variant, typename... VisitorArg>
  532. auto visit(Visitor &visitor, const Variant& var, VisitorArg &&...args) -> decltype(visitor(get<0>(var)))
  533. {
  534. constexpr std::size_t varsize = util::variant_size<Variant>::value;
  535. static_assert(varsize != 0, "utils::variant must contains one type at least ");
  536. using is_variant_processed_t = std::false_type;
  537. using ReturnType = decltype(visitor(get<0>(var)));
  538. using return_t = std::is_same<ReturnType, void>;
  539. return detail::apply_visitor_impl<ReturnType, 0, varsize, Visitor>(
  540. std::forward<Visitor>(visitor),
  541. var, is_variant_processed_t{},
  542. return_t{},
  543. std::forward<VisitorArg>(args)...);
  544. }
  545. template<typename Visitor, typename Variant>
  546. auto visit(Visitor&& visitor, const Variant& var) -> decltype(visitor(get<0>(var)))
  547. {
  548. constexpr std::size_t varsize = util::variant_size<Variant>::value;
  549. static_assert(varsize != 0, "utils::variant must contains one type at least ");
  550. using is_variant_processed_t = std::false_type;
  551. using ReturnType = decltype(visitor(get<0>(var)));
  552. using return_t = std::is_same<ReturnType, void>;
  553. return detail::apply_visitor_impl<ReturnType, 0, varsize, Visitor>(
  554. std::forward<Visitor>(visitor),
  555. var, is_variant_processed_t{},
  556. return_t{});
  557. }
  558. } // namespace util
  559. } // namespace cv
  560. #endif // OPENCV_GAPI_UTIL_VARIANT_HPP