From ee2e33507221ee3ab4a1be43442844461b892b3d Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Fri, 10 Apr 2020 07:45:15 +0200 Subject: [PATCH] do not copy the variant in its visitor --- alib2std/src/extensions/container/variant.hpp | 35 ++++---- .../extensions/container/VariantTest.cpp | 82 +++++++++++++++++++ 2 files changed, 101 insertions(+), 16 deletions(-) diff --git a/alib2std/src/extensions/container/variant.hpp b/alib2std/src/extensions/container/variant.hpp index c01ddbe70a..8c8194e7f3 100644 --- a/alib2std/src/extensions/container/variant.hpp +++ b/alib2std/src/extensions/container/variant.hpp @@ -40,21 +40,7 @@ namespace ext { template < class Visitor, class... Variants > constexpr auto visit ( Visitor && vis, Variants && ... vars ) { - auto extToStd = [] ( auto && variant ) { - using __std__variant = typename std::decay_t < decltype ( variant ) >::__base; - - if constexpr ( std::is_lvalue_reference_v < decltype ( variant ) > && std::is_const_v < std::remove_reference_t < decltype ( variant ) > > ) { - return static_cast < const __std__variant & > ( variant ); - } else if constexpr ( std::is_lvalue_reference_v < decltype ( variant ) > ) { - return static_cast < __std__variant & > ( variant ); - } else if constexpr ( std::is_rvalue_reference_v < decltype ( variant ) > ) { - return static_cast < __std__variant && > ( variant ); - } else { - static_assert ( "Unhandled option" ); - } - }; - - return std::visit ( std::forward < Visitor > ( vis ), extToStd ( std::forward < Variants > ( vars ) ) ... ); + return std::visit ( std::forward < Visitor > ( vis ), std::forward < Variants > ( vars ).asStdVariant ( ) ... ); } /** @@ -107,6 +93,10 @@ using __std__variant = typename variant_builder_start < Ts ... >::__std__variant */ template < typename ... Ts > class variant : public __std__variant < Ts ... > { + + template < class Visitor, class... Variants > + friend constexpr auto visit ( Visitor && vis, Variants && ... vars ); + /** * Internal variant to string callback implementation. */ @@ -178,12 +168,25 @@ class variant : public __std__variant < Ts ... > { return - second.compare ( first ); } }; -public: + /** * Remember the base class, i.e. std::variant */ typedef __std__variant < Ts ... > __base; + const __base & asStdVariant ( ) const & { + return * this; + } + + __base & asStdVariant ( ) & { + return * this; + } + + __base && asStdVariant ( ) && { + return std::move ( * this ); + } + +public: /** * Inherit constructors of the standard variant */ diff --git a/alib2std/test-src/extensions/container/VariantTest.cpp b/alib2std/test-src/extensions/container/VariantTest.cpp index 4294e1edf7..3d44695bc9 100644 --- a/alib2std/test-src/extensions/container/VariantTest.cpp +++ b/alib2std/test-src/extensions/container/VariantTest.cpp @@ -68,6 +68,51 @@ namespace { test2(int i) : m_i(i) {} }; + + class Moveable { + int& m_moves; + int& m_copies; + + public: + Moveable(int& moves, int& copies) : m_moves(moves), m_copies(copies) { + m_moves = 0; + m_copies = 0; + } + + Moveable(const Moveable& src) : m_moves(src.m_moves), m_copies(src.m_copies) { + m_copies++; + } + + Moveable(Moveable&& src) : m_moves(src.m_moves), m_copies(src.m_copies) { + m_moves++; + } + + Moveable & operator = ( const Moveable & ) { + m_copies ++; + return * this; + } + + Moveable & operator = ( Moveable && ) { + m_moves ++; + return * this; + } + + bool operator<(const Moveable&) const { + return false; + } + + bool operator==(const Moveable&) const { + return true; + } + + bool operator!=(const Moveable&) const { + return false; + } + + friend std::ostream & operator << ( std::ostream & os, const Moveable & ) { + return os << "Moveable"; + } + }; } namespace ext { @@ -79,6 +124,13 @@ namespace ext { } }; + template<> + struct compare<Moveable> { + int operator()(const Moveable& , const Moveable& ) { + return 0; + } + }; + } /* namespace ext */ TEST_CASE ( "Variant", "[unit][std][container]" ) { @@ -232,4 +284,34 @@ TEST_CASE ( "Variant", "[unit][std][container]" ) { v = std::move ( v2 ); v.get < std::set < int > > ( ).insert ( 1 ); } + + SECTION ( "Copy vs. Move" ) { + int moves = 0; + int copies = 0; + + ext::variant < Moveable, int > inst1 ( Moveable ( moves, copies ) ); + + CHECK ( moves == 1 ); + CHECK ( copies == 0 ); + + ext::variant < Moveable, int > inst2 ( 1 ); + + CHECK ( moves == 1 ); + CHECK ( copies == 0 ); + + CHECK ( inst1 != inst2 ); + + CHECK ( moves == 1 ); + CHECK ( copies == 0 ); + + std::cout << inst1 << std::endl; + + CHECK ( moves == 1 ); + CHECK ( copies == 0 ); + + inst1.compare ( inst2 ); + + CHECK ( moves == 1 ); + CHECK ( copies == 0 ); + } } -- GitLab