const_ref_apply_visitor.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. // Copyright (c) 2017 Levon Tarakchyan
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #include "boost/config.hpp"
  7. #include "boost/core/lightweight_test.hpp"
  8. #include "boost/variant.hpp"
  9. #include "boost/variant/apply_visitor.hpp"
  10. #include "boost/variant/multivisitors.hpp"
  11. #include "boost/lexical_cast.hpp"
  12. #define lcs(val) boost::lexical_cast<std::string>(val)
  13. struct construction_logger
  14. {
  15. int val_;
  16. construction_logger(int val) : val_(val)
  17. {
  18. std::cout << val_ << " constructed\n";
  19. }
  20. construction_logger(const construction_logger& cl) :
  21. val_(cl.val_)
  22. {
  23. std::cout << val_ << " copy constructed\n";
  24. }
  25. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  26. construction_logger(construction_logger&& cl) :
  27. val_(cl.val_)
  28. {
  29. std::cout << val_ << " move constructed\n";
  30. }
  31. #endif
  32. friend std::ostream& operator << (std::ostream& os, const construction_logger& cl)
  33. {
  34. return os << cl.val_;
  35. }
  36. friend std::istream& operator << (std::istream& is, construction_logger& cl)
  37. {
  38. return is >> cl.val_;
  39. }
  40. };
  41. struct lex_streamer_explicit : boost::static_visitor<std::string>
  42. {
  43. template <class T>
  44. std::string operator()(const T& val) const
  45. {
  46. return lcs(val);
  47. }
  48. template <class T, class V>
  49. std::string operator()(const T& val, const V& val2) const
  50. {
  51. return lcs(val) + '+' + lcs(val2);
  52. }
  53. template <class T, class V, class P, class S>
  54. std::string operator()(const T& val, const V& val2, const P& val3, const S& val4) const
  55. {
  56. return lcs(val) + '+' + lcs(val2) + '+' + lcs(val3) + '+' + lcs(val4);
  57. }
  58. };
  59. struct lvalue_rvalue_detector : boost::static_visitor<std::string>
  60. {
  61. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  62. template <class T>
  63. std::string operator()(T&&) const
  64. {
  65. return std::is_lvalue_reference<T>::value ? "lvalue reference"
  66. : "rvalue reference";
  67. }
  68. template <class T, class V>
  69. std::string operator()(T&& t, V&& v) const
  70. {
  71. return operator()(std::forward<T>(t)) + ", " + operator()(std::forward<V>(v));
  72. }
  73. template <class T, class V, class P>
  74. std::string operator()(T&& t, V&& v, P&& p) const
  75. {
  76. return operator()(std::forward<T>(t), std::forward<V>(v)) + ", " + operator()(std::forward<P>(p));
  77. }
  78. template <class T, class V, class P, class S>
  79. std::string operator()(T&& t, V&& v, P&& p, S&& s) const
  80. {
  81. return operator()(std::forward<T>(t), std::forward<V>(v), std::forward<P>(p)) + ", " + operator()(std::forward<S>(s));
  82. }
  83. #else
  84. template <class T>
  85. std::string operator()(T&) const
  86. {
  87. return "lvalue reference";
  88. }
  89. template <class T, class V>
  90. std::string operator()(T&, V&) const
  91. {
  92. return "lvalue reference, lvalue reference";
  93. }
  94. template <class T, class V, class P>
  95. std::string operator()(T&, V&, P&) const
  96. {
  97. return "lvalue reference, lvalue reference, lvalue reference";
  98. }
  99. template <class T, class V, class P, class S>
  100. std::string operator()(T&, V&, P&, S&) const
  101. {
  102. return "lvalue reference, lvalue reference, lvalue reference, lvalue reference";
  103. }
  104. #endif
  105. };
  106. typedef boost::variant<construction_logger, std::string> variant_type;
  107. void test_const_ref_parameter(const variant_type& test_var)
  108. {
  109. std::cout << "Testing const lvalue reference visitable\n";
  110. BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), test_var) == "lvalue reference");
  111. }
  112. void test_const_ref_parameter2(const variant_type& test_var, const variant_type& test_var2)
  113. {
  114. std::cout << "Testing const lvalue reference visitable\n";
  115. BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), test_var, test_var2) == "lvalue reference, lvalue reference");
  116. }
  117. void test_const_ref_parameter4(const variant_type& test_var, const variant_type& test_var2, const variant_type& test_var3, const variant_type& test_var4)
  118. {
  119. std::cout << "Testing const lvalue reference visitable with multivisitor\n";
  120. BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), test_var, test_var2, test_var3, test_var4)
  121. == "lvalue reference, lvalue reference, lvalue reference, lvalue reference");
  122. }
  123. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_REF_QUALIFIERS)
  124. void test_rvalue_parameter(variant_type&& test_var)
  125. {
  126. std::cout << "Testing rvalue visitable\n";
  127. const auto expected_val = lcs(test_var);
  128. BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), std::move(test_var)) == "rvalue reference");
  129. }
  130. void test_rvalue_parameter2(variant_type&& test_var, variant_type&& test_var2)
  131. {
  132. std::cout << "Testing rvalue visitable\n";
  133. BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), std::move(test_var), std::move(test_var2)) == "rvalue reference, rvalue reference");
  134. }
  135. void test_rvalue_parameter4(variant_type&& test_var, variant_type&& test_var2, variant_type&& test_var3, variant_type&& test_var4)
  136. {
  137. #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
  138. std::cout << "Testing rvalue visitable with multivisitor\n";
  139. auto result = boost::apply_visitor(lvalue_rvalue_detector(), std::move(test_var), std::move(test_var2), std::move(test_var3), std::move(test_var4));
  140. std::cout << "result: " << result << std::endl;
  141. BOOST_TEST(result == "rvalue reference, rvalue reference, rvalue reference, rvalue reference");
  142. #else
  143. (void)test_var;
  144. (void)test_var2;
  145. (void)test_var3;
  146. (void)test_var4;
  147. #endif
  148. }
  149. #endif
  150. #ifndef BOOST_NO_CXX14_DECLTYPE_AUTO
  151. #define FORWARD(x) std::forward<decltype(x)>(x)
  152. void test_cpp14_visitor(const variant_type& test_var)
  153. {
  154. std::cout << "Testing const lvalue visitable for c++14\n";
  155. BOOST_TEST(boost::apply_visitor([](auto&& v) { return lvalue_rvalue_detector()(FORWARD(v)); }, test_var) == "lvalue reference");
  156. }
  157. void test_cpp14_mutable_visitor(const variant_type& test_var)
  158. {
  159. std::cout << "Testing const lvalue visitable for c++14 with inline mutable lambda\n";
  160. BOOST_TEST(boost::apply_visitor([](auto&& v) mutable -> auto { return lvalue_rvalue_detector()(FORWARD(v)); }, test_var) == "lvalue reference");
  161. }
  162. void test_cpp14_visitor(const variant_type& test_var, const variant_type& test_var2)
  163. {
  164. std::cout << "Testing const lvalue visitable for c++14\n";
  165. BOOST_TEST(boost::apply_visitor([](auto&& v, auto&& vv) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(vv)); }, test_var, test_var2)
  166. == "lvalue reference, lvalue reference");
  167. }
  168. void test_cpp14_visitor(const variant_type& test_var, const variant_type& test_var2, const variant_type& test_var3)
  169. {
  170. #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
  171. std::cout << "Testing const lvalue visitable for c++14\n";
  172. auto result = boost::apply_visitor([](auto&& v, auto&& t, auto&& p) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t), FORWARD(p)); },
  173. test_var, test_var2, test_var3);
  174. std::cout << "result: " << result << std::endl;
  175. BOOST_TEST(result == "lvalue reference, lvalue reference, lvalue reference");
  176. #else
  177. (void)test_var;
  178. (void)test_var2;
  179. (void)test_var3;
  180. #endif
  181. }
  182. void test_cpp14_visitor(variant_type& test_var)
  183. {
  184. std::cout << "Testing lvalue visitable for c++14\n";
  185. BOOST_TEST(boost::apply_visitor([](auto& v) { return lvalue_rvalue_detector()(v); }, test_var) == "lvalue reference");
  186. }
  187. void test_cpp14_mutable_visitor(variant_type& test_var)
  188. {
  189. std::cout << "Testing lvalue visitable for c++14 with inline mutable lambda\n";
  190. BOOST_TEST(boost::apply_visitor([](auto& v) mutable -> auto { return lvalue_rvalue_detector()(v); }, test_var) == "lvalue reference");
  191. }
  192. void test_cpp14_visitor(variant_type& test_var, variant_type& test_var2)
  193. {
  194. std::cout << "Testing lvalue visitable for c++14\n";
  195. BOOST_TEST(boost::apply_visitor([](auto& v, auto& vv) { return lvalue_rvalue_detector()(v, vv); }, test_var, test_var2)
  196. == "lvalue reference, lvalue reference");
  197. }
  198. void test_cpp14_visitor(variant_type& test_var, variant_type& test_var2, variant_type& test_var3)
  199. {
  200. #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
  201. std::cout << "Testing lvalue visitable for c++14\n";
  202. auto result = boost::apply_visitor([](auto& v, auto& t, auto& p) { return lvalue_rvalue_detector()(v, t, p); },
  203. test_var, test_var2, test_var3);
  204. std::cout << "result: " << result << std::endl;
  205. BOOST_TEST(result == "lvalue reference, lvalue reference, lvalue reference");
  206. #else
  207. (void)test_var;
  208. (void)test_var2;
  209. (void)test_var3;
  210. #endif
  211. }
  212. void test_cpp14_visitor(variant_type&& test_var)
  213. {
  214. std::cout << "Testing rvalue visitable for c++14\n";
  215. BOOST_TEST(boost::apply_visitor([](auto&& v) { return lvalue_rvalue_detector()(FORWARD(v)); }, std::move(test_var)) == "rvalue reference");
  216. }
  217. void test_cpp14_visitor(variant_type&& test_var, variant_type&& test_var2)
  218. {
  219. std::cout << "Testing rvalue visitable for c++14\n";
  220. BOOST_TEST(boost::apply_visitor([](auto&& v, auto&& vv) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(vv)); }, std::move(test_var), std::move(test_var2))
  221. == "rvalue reference, rvalue reference");
  222. }
  223. void test_cpp14_visitor(variant_type&& test_var, variant_type&& test_var2, variant_type&& test_var3)
  224. {
  225. #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
  226. std::cout << "Testing rvalue visitable for c++14\n";
  227. auto result = boost::apply_visitor([](auto&& v, auto&& t, auto&& p) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t), FORWARD(p)); },
  228. std::move(test_var), std::move(test_var2), std::move(test_var3));
  229. std::cout << "result: " << result << std::endl;
  230. BOOST_TEST(result == "rvalue reference, rvalue reference, rvalue reference");
  231. #else
  232. (void)test_var;
  233. (void)test_var2;
  234. (void)test_var3;
  235. #endif
  236. }
  237. #endif
  238. void run_const_lvalue_ref_tests()
  239. {
  240. const variant_type v1(1), v2(2), v3(3), v4(4);
  241. test_const_ref_parameter(v1);
  242. test_const_ref_parameter2(v1, v2);
  243. test_const_ref_parameter4(v1, v2, v3, v4);
  244. }
  245. void run_rvalue_ref_tests()
  246. {
  247. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_REF_QUALIFIERS)
  248. variant_type v1(10), v2(20), v3(30);
  249. test_rvalue_parameter(boost::move(v1));
  250. test_rvalue_parameter2(boost::move(v2), boost::move(v3));
  251. variant_type vv1(100), vv2(200), vv3(300), vv4(400);
  252. test_rvalue_parameter4(boost::move(vv1), boost::move(vv2), boost::move(vv3), boost::move(vv4));
  253. #endif
  254. }
  255. void run_mixed_tests()
  256. {
  257. variant_type v1(1), v2(2);
  258. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  259. #ifndef BOOST_NO_CXX11_REF_QUALIFIERS
  260. std::cout << "Testing lvalue + rvalue visitable\n";
  261. BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), v1, variant_type(10)) == "lvalue reference, rvalue reference");
  262. std::cout << "Testing rvalue + lvalue visitable\n";
  263. BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), variant_type(10), v1) == "rvalue reference, lvalue reference");
  264. #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
  265. std::cout << "Testing rvalue + lvalue + rvalue visitable\n";
  266. BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), variant_type(10), v1, variant_type(20)) == "rvalue reference, lvalue reference, rvalue reference");
  267. std::cout << "Testing lvalue + rvalue + lvalue + rvalue visitable\n";
  268. BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), v1, variant_type(10), v2, variant_type(20)) == "lvalue reference, rvalue reference, lvalue reference, rvalue reference");
  269. #endif
  270. #endif // #ifndef BOOST_NO_CXX11_REF_QUALIFIERS
  271. #else // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  272. std::cout << "Testing lvalue + rvalue visitable\n";
  273. BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), v1, v1) == "lvalue reference, lvalue reference");
  274. std::cout << "Testing rvalue + lvalue visitable\n";
  275. BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), static_cast<const variant_type&>(variant_type(10)), v1) == "lvalue reference, lvalue reference");
  276. #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
  277. std::cout << "Testing rvalue + lvalue + rvalue visitable\n";
  278. BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), static_cast<const variant_type&>(variant_type(10)), v1, static_cast<const variant_type&>(variant_type(20))) == "lvalue reference, lvalue reference, lvalue reference");
  279. std::cout << "Testing lvalue + rvalue + lvalue + rvalue visitable\n";
  280. BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), v1, static_cast<const variant_type&>(variant_type(10)), v2, static_cast<const variant_type&>(variant_type(20))) == "lvalue reference, lvalue reference, lvalue reference, lvalue reference");
  281. #endif
  282. #endif
  283. }
  284. void run_cpp14_mixed_tests()
  285. {
  286. #ifndef BOOST_NO_CXX14_DECLTYPE_AUTO
  287. variant_type v1(1), v2(2);
  288. std::cout << "Testing lvalue + rvalue visitable\n";
  289. BOOST_TEST(boost::apply_visitor([](auto&& v, auto&& t) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t)); },
  290. v1, variant_type(10)) == "lvalue reference, rvalue reference");
  291. std::cout << "Testing rvalue + lvalue visitable\n";
  292. BOOST_TEST(boost::apply_visitor([](auto&& v, auto&& t) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t)); },
  293. variant_type(10), v1) == "rvalue reference, lvalue reference");
  294. #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
  295. std::cout << "Testing rvalue + lvalue + lvalue visitable\n";
  296. BOOST_TEST(boost::apply_visitor([](auto&& v, auto&& t, auto&& p) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t), FORWARD(p)); },
  297. variant_type(10), v1, v2) == "rvalue reference, lvalue reference, lvalue reference");
  298. std::cout << "Testing lvalue + rvalue + lvalue visitable\n";
  299. BOOST_TEST(boost::apply_visitor([](auto&& v, auto&& t, auto&& p) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t), FORWARD(p)); },
  300. v1, variant_type(10), v2) == "lvalue reference, rvalue reference, lvalue reference");
  301. #endif
  302. #endif
  303. }
  304. void run_cpp14_tests()
  305. {
  306. #ifndef BOOST_NO_CXX14_DECLTYPE_AUTO
  307. variant_type const c1(10), c2(20), c3(30);
  308. variant_type v1(10), v2(20), v3(30);
  309. test_cpp14_visitor(c1);
  310. test_cpp14_mutable_visitor(c1);
  311. test_cpp14_visitor(c2, c3);
  312. test_cpp14_visitor(c1, c2, c3);
  313. test_cpp14_visitor(v1);
  314. test_cpp14_mutable_visitor(v1);
  315. test_cpp14_visitor(v2, v3);
  316. test_cpp14_visitor(v1, v2, v3);
  317. test_cpp14_visitor(boost::move(v1));
  318. test_cpp14_visitor(boost::move(v2), boost::move(v3));
  319. variant_type vv1(100), vv2(200), vv3(300);
  320. test_cpp14_visitor(boost::move(vv1), boost::move(vv2), boost::move(vv3));
  321. #endif
  322. }
  323. int main()
  324. {
  325. run_const_lvalue_ref_tests();
  326. run_rvalue_ref_tests();
  327. run_mixed_tests();
  328. run_cpp14_mixed_tests();
  329. run_cpp14_tests();
  330. return boost::report_errors();
  331. }