[Git][debian-gis-team/mapbox-variant][upstream] New upstream version 1.2.0

Bas Couwenberg gitlab at salsa.debian.org
Mon Aug 3 16:00:54 BST 2020



Bas Couwenberg pushed to branch upstream at Debian GIS Project / mapbox-variant


Commits:
d010b70e by Bas Couwenberg at 2020-08-03T16:53:39+02:00
New upstream version 1.2.0
- - - - -


9 changed files:

- .travis.yml
- CHANGELOG.md
- Makefile
- include/mapbox/variant.hpp
- test/compilation_failure/get_type.cpp
- test/compilation_failure/mutating_visitor_on_const.cpp
- test/lambda_overload_test.cpp
- test/t/optional.cpp
- + test/t/visitor_result_type.cpp


Changes:

=====================================
.travis.yml
=====================================
@@ -89,20 +89,6 @@ matrix:
         apt:
           sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6' ]
           packages: [ 'clang-3.6' ]
-    - os: linux
-      compiler: "clang37"
-      env: CXX=clang++-3.7
-      addons:
-        apt:
-          sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7' ]
-          packages: [ 'clang-3.7' ]
-    - os: linux
-      compiler: "gcc47"
-      env: CXX=g++-4.7 CXXFLAGS="-Wno-parentheses"
-      addons:
-        apt:
-          sources: [ 'ubuntu-toolchain-r-test' ]
-          packages: [ 'g++-4.7' ]
     - os: linux
       compiler: "gcc48"
       env: CXX=g++-4.8
@@ -145,6 +131,7 @@ install:
 
 script:
  # Build in Release
+ - make
  - make test
  - make bench
  - make sizes
@@ -152,6 +139,7 @@ script:
  - make clean;
  # Build in Debug
  - export BUILDTYPE=Debug
+ - make
  - make test
  - make bench
  - make sizes


=====================================
CHANGELOG.md
=====================================
@@ -1,5 +1,17 @@
 # Variant changelog
 
+## 1.2.0
+
+Released: July 3, 2020
+
+(82f9561)
+
+* Use perfect forwarding for internal value types deductions (#178) (#180)
+* Implement support for "moving" values out (#142) (#178) (#180)
+* Preserve ability to specify explicit `return_type` in visitors (#181)
+* Add self-assignment checks in copy and move assignment operator= (#164)
+* Add relevant tests
+
 ## 1.1.6
 
 Released: April 25, 2019


=====================================
Makefile
=====================================
@@ -99,7 +99,25 @@ out/%.o: test/t/%.cpp Makefile $(ALL_HEADERS)
 	mkdir -p ./out
 	$(CXX) -c -o $@ $< -Iinclude -isystem test/include $(FINAL_CXXFLAGS)
 
-out/unit: out/unit.o out/binary_visitor_1.o out/binary_visitor_2.o out/binary_visitor_3.o out/binary_visitor_4.o out/binary_visitor_5.o out/binary_visitor_6.o out/issue21.o out/issue122.o out/mutating_visitor.o out/optional.o out/recursive_wrapper.o out/sizeof.o out/unary_visitor.o out/variant.o out/variant_alternative.o out/nothrow_move.o
+out/unit: out/unit.o \
+          out/binary_visitor_1.o \
+          out/binary_visitor_2.o \
+          out/binary_visitor_3.o \
+          out/binary_visitor_4.o \
+          out/binary_visitor_5.o \
+          out/binary_visitor_6.o \
+          out/issue21.o \
+          out/issue122.o \
+          out/mutating_visitor.o \
+          out/optional.o \
+          out/recursive_wrapper.o \
+          out/sizeof.o \
+          out/unary_visitor.o \
+          out/variant.o \
+          out/variant_alternative.o \
+          out/nothrow_move.o \
+          out/visitor_result_type.o \
+
 	mkdir -p ./out
 	$(CXX) -o $@ $^ $(LDFLAGS)
 


=====================================
include/mapbox/variant.hpp
=====================================
@@ -171,36 +171,57 @@ struct value_traits
     using target_type = typename std::tuple_element<tindex, std::tuple<void, Types...>>::type;
 };
 
-template <typename T, typename R = void>
-struct enable_if_type
+template <typename Src, typename Dest>
+struct copy_cvref
 {
-    using type = R;
+    using type = Dest;
 };
 
-template <typename F, typename V, typename Enable = void>
-struct result_of_unary_visit
+template <typename Src, typename Dest>
+struct copy_cvref<Src const&, Dest>
 {
-    using type = typename std::result_of<F(V&)>::type;
+    using type = Dest const&;
 };
 
-template <typename F, typename V>
-struct result_of_unary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
+template <typename Src, typename Dest>
+struct copy_cvref<Src&, Dest>
 {
-    using type = typename F::result_type;
+    using type = Dest&;
 };
 
-template <typename F, typename V, typename Enable = void>
-struct result_of_binary_visit
+template <typename Src, typename Dest>
+struct copy_cvref<Src&&, Dest>
 {
-    using type = typename std::result_of<F(V&, V&)>::type;
+    using type = Dest&&;
 };
 
-template <typename F, typename V>
-struct result_of_binary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
+template <typename F, typename = void>
+struct deduced_result_type
+{};
+
+template <typename F, typename... Args>
+struct deduced_result_type<F(Args...), decltype((void)std::declval<F>()(std::declval<Args>()...))>
+{
+    using type = decltype(std::declval<F>()(std::declval<Args>()...));
+};
+
+template <typename F, typename = void>
+struct visitor_result_type : deduced_result_type<F>
+{};
+
+// specialization for explicit result_type member in visitor class
+template <typename F, typename... Args>
+struct visitor_result_type<F(Args...), decltype((void)std::declval<typename std::decay<F>::type::result_type>())>
 {
-    using type = typename F::result_type;
+    using type = typename std::decay<F>::type::result_type;
 };
 
+template <typename F, typename T>
+using result_of_unary_visit = typename visitor_result_type<F&&(T&&)>::type;
+
+template <typename F, typename T>
+using result_of_binary_visit = typename visitor_result_type<F&&(T&&, T&&)>::type;
+
 template <type_index_t arg1, type_index_t... others>
 struct static_max;
 
@@ -270,245 +291,174 @@ struct variant_helper<>
 template <typename T>
 struct unwrapper
 {
-    static T const& apply_const(T const& obj) { return obj; }
-    static T& apply(T& obj) { return obj; }
-};
+    using value_type = T;
 
-template <typename T>
-struct unwrapper<recursive_wrapper<T>>
-{
-    static auto apply_const(recursive_wrapper<T> const& obj)
-        -> typename recursive_wrapper<T>::type const&
+    template <typename V>
+    static auto apply(typename std::remove_reference<V>::type& var)
+        -> typename std::enable_if<std::is_lvalue_reference<V>::value,
+                    decltype(var.template get_unchecked<T>())>::type
     {
-        return obj.get();
+        return var.template get_unchecked<T>();
     }
-    static auto apply(recursive_wrapper<T>& obj)
-        -> typename recursive_wrapper<T>::type&
+
+    template <typename V>
+    static auto apply(typename std::remove_reference<V>::type& var)
+        -> typename std::enable_if<!std::is_lvalue_reference<V>::value,
+                    decltype(std::move(var.template get_unchecked<T>()))>::type
     {
-        return obj.get();
+        return std::move(var.template get_unchecked<T>());
     }
 };
 
 template <typename T>
-struct unwrapper<std::reference_wrapper<T>>
-{
-    static auto apply_const(std::reference_wrapper<T> const& obj)
-        -> typename std::reference_wrapper<T>::type const&
-    {
-        return obj.get();
-    }
-    static auto apply(std::reference_wrapper<T>& obj)
-        -> typename std::reference_wrapper<T>::type&
-    {
-        return obj.get();
-    }
-};
+struct unwrapper<recursive_wrapper<T>> : unwrapper<T>
+{};
+
+template <typename T>
+struct unwrapper<std::reference_wrapper<T>> : unwrapper<T>
+{};
 
-template <typename F, typename V, typename R, typename... Types>
+template <typename R, typename... Types>
 struct dispatcher;
 
-template <typename F, typename V, typename R, typename T, typename... Types>
-struct dispatcher<F, V, R, T, Types...>
+template <typename R, typename T, typename... Types>
+struct dispatcher<R, T, Types...>
 {
-    VARIANT_INLINE static R apply_const(V const& v, F&& f)
-    {
-        if (v.template is<T>())
-        {
-            return f(unwrapper<T>::apply_const(v.template get_unchecked<T>()));
-        }
-        else
-        {
-            return dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
-        }
-    }
-
-    VARIANT_INLINE static R apply(V& v, F&& f)
+    template <typename V, typename F>
+    VARIANT_INLINE static R apply(V&& v, F&& f)
     {
         if (v.template is<T>())
         {
-            return f(unwrapper<T>::apply(v.template get_unchecked<T>()));
+            return std::forward<F>(f)(unwrapper<T>::template apply<V>(v));
         }
         else
         {
-            return dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
+            return dispatcher<R, Types...>::apply(std::forward<V>(v), std::forward<F>(f));
         }
     }
 };
 
-template <typename F, typename V, typename R, typename T>
-struct dispatcher<F, V, R, T>
+template <typename R, typename T>
+struct dispatcher<R, T>
 {
-    VARIANT_INLINE static R apply_const(V const& v, F&& f)
+    template <typename V, typename F>
+    VARIANT_INLINE static R apply(V&& v, F&& f)
     {
-        return f(unwrapper<T>::apply_const(v.template get_unchecked<T>()));
-    }
-
-    VARIANT_INLINE static R apply(V& v, F&& f)
-    {
-        return f(unwrapper<T>::apply(v.template get_unchecked<T>()));
+        return std::forward<F>(f)(unwrapper<T>::template apply<V>(v));
     }
 };
 
-template <typename F, typename V, typename R, typename T, typename... Types>
+template <typename R, typename T, typename... Types>
 struct binary_dispatcher_rhs;
 
-template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
-struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
+template <typename R, typename T0, typename T1, typename... Types>
+struct binary_dispatcher_rhs<R, T0, T1, Types...>
 {
-    VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
-    {
-        if (rhs.template is<T1>()) // call binary functor
-        {
-            return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
-                     unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>()));
-        }
-        else
-        {
-            return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
-        }
-    }
-
-    VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
+    template <typename V, typename F>
+    VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f)
     {
         if (rhs.template is<T1>()) // call binary functor
         {
-            return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
-                     unwrapper<T1>::apply(rhs.template get_unchecked<T1>()));
+            return std::forward<F>(f)(unwrapper<T0>::template apply<V>(lhs),
+                                      unwrapper<T1>::template apply<V>(rhs));
         }
         else
         {
-            return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
+            return binary_dispatcher_rhs<R, T0, Types...>::apply(std::forward<V>(lhs),
+                                                                 std::forward<V>(rhs),
+                                                                 std::forward<F>(f));
         }
     }
 };
 
-template <typename F, typename V, typename R, typename T0, typename T1>
-struct binary_dispatcher_rhs<F, V, R, T0, T1>
+template <typename R, typename T0, typename T1>
+struct binary_dispatcher_rhs<R, T0, T1>
 {
-    VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
+    template <typename V, typename F>
+    VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f)
     {
-        return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
-                 unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>()));
-    }
-
-    VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
-    {
-        return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
-                 unwrapper<T1>::apply(rhs.template get_unchecked<T1>()));
+        return std::forward<F>(f)(unwrapper<T0>::template apply<V>(lhs),
+                                  unwrapper<T1>::template apply<V>(rhs));
     }
 };
 
-template <typename F, typename V, typename R, typename T, typename... Types>
+template <typename R, typename T, typename... Types>
 struct binary_dispatcher_lhs;
 
-template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
-struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
+template <typename R, typename T0, typename T1, typename... Types>
+struct binary_dispatcher_lhs<R, T0, T1, Types...>
 {
-    VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
+    template <typename V, typename F>
+    VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f)
     {
         if (lhs.template is<T1>()) // call binary functor
         {
-            return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
-                     unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>()));
+            return std::forward<F>(f)(unwrapper<T1>::template apply<V>(lhs),
+                                      unwrapper<T0>::template apply<V>(rhs));
         }
         else
         {
-            return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
-        }
-    }
-
-    VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
-    {
-        if (lhs.template is<T1>()) // call binary functor
-        {
-            return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
-                     unwrapper<T0>::apply(rhs.template get_unchecked<T0>()));
-        }
-        else
-        {
-            return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
+            return binary_dispatcher_lhs<R, T0, Types...>::apply(std::forward<V>(lhs),
+                                                                 std::forward<V>(rhs),
+                                                                 std::forward<F>(f));
         }
     }
 };
 
-template <typename F, typename V, typename R, typename T0, typename T1>
-struct binary_dispatcher_lhs<F, V, R, T0, T1>
+template <typename R, typename T0, typename T1>
+struct binary_dispatcher_lhs<R, T0, T1>
 {
-    VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
+    template <typename V, typename F>
+    VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f)
     {
-        return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
-                 unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>()));
-    }
-
-    VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
-    {
-        return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
-                 unwrapper<T0>::apply(rhs.template get_unchecked<T0>()));
+        return std::forward<F>(f)(unwrapper<T1>::template apply<V>(lhs),
+                                  unwrapper<T0>::template apply<V>(rhs));
     }
 };
 
-template <typename F, typename V, typename R, typename... Types>
+template <typename R, typename... Types>
 struct binary_dispatcher;
 
-template <typename F, typename V, typename R, typename T, typename... Types>
-struct binary_dispatcher<F, V, R, T, Types...>
+template <typename R, typename T, typename... Types>
+struct binary_dispatcher<R, T, Types...>
 {
-    VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
-    {
-        if (v0.template is<T>())
-        {
-            if (v1.template is<T>())
-            {
-                return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()),
-                         unwrapper<T>::apply_const(v1.template get_unchecked<T>())); // call binary functor
-            }
-            else
-            {
-                return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
-            }
-        }
-        else if (v1.template is<T>())
-        {
-            return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
-        }
-        return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
-    }
-
-    VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
+    template <typename V, typename F>
+    VARIANT_INLINE static R apply(V&& v0, V&& v1, F&& f)
     {
         if (v0.template is<T>())
         {
             if (v1.template is<T>())
             {
-                return f(unwrapper<T>::apply(v0.template get_unchecked<T>()),
-                         unwrapper<T>::apply(v1.template get_unchecked<T>())); // call binary functor
+                return std::forward<F>(f)(unwrapper<T>::template apply<V>(v0),
+                                          unwrapper<T>::template apply<V>(v1)); // call binary functor
             }
             else
             {
-                return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
+                return binary_dispatcher_rhs<R, T, Types...>::apply(std::forward<V>(v0),
+                                                                    std::forward<V>(v1),
+                                                                    std::forward<F>(f));
             }
         }
         else if (v1.template is<T>())
         {
-            return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
+            return binary_dispatcher_lhs<R, T, Types...>::apply(std::forward<V>(v0),
+                                                                std::forward<V>(v1),
+                                                                std::forward<F>(f));
         }
-        return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
+        return binary_dispatcher<R, Types...>::apply(std::forward<V>(v0),
+                                                     std::forward<V>(v1),
+                                                     std::forward<F>(f));
     }
 };
 
-template <typename F, typename V, typename R, typename T>
-struct binary_dispatcher<F, V, R, T>
+template <typename R, typename T>
+struct binary_dispatcher<R, T>
 {
-    VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
+    template <typename V, typename F>
+    VARIANT_INLINE static R apply(V&& v0, V&& v1, F&& f)
     {
-        return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()),
-                 unwrapper<T>::apply_const(v1.template get_unchecked<T>())); // call binary functor
-    }
-
-    VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
-    {
-        return f(unwrapper<T>::apply(v0.template get_unchecked<T>()),
-                 unwrapper<T>::apply(v1.template get_unchecked<T>())); // call binary functor
+        return std::forward<F>(f)(unwrapper<T>::template apply<V>(v0),
+                                  unwrapper<T>::template apply<V>(v1)); // call binary functor
     }
 };
 
@@ -579,16 +529,20 @@ public:
     using types = std::tuple<Types...>;
 private:
     using first_type = typename std::tuple_element<0, types>::type;
+    using unwrap_first_type = typename detail::unwrapper<first_type>::value_type;
     using data_type = typename std::aligned_storage<data_size, data_align>::type;
     using helper_type = detail::variant_helper<Types...>;
 
+    template <typename V, typename T = unwrap_first_type>
+        using alternative_ref = typename detail::copy_cvref<V, T>::type;
+
     type_index_t type_index;
 #ifdef __clang_analyzer__
     data_type data {};
 #else
     data_type data;
 #endif
-    
+
 public:
     VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible<first_type>::value)
         : type_index(sizeof...(Types)-1)
@@ -645,13 +599,18 @@ public:
         // move_assign uses move-construction via placement new.
         noexcept(detail::conjunction<std::is_nothrow_move_constructible<Types>...>::value)
     {
+        if (this == &other) { // playing safe in release mode, hit assertion in debug.
+            assert(false);
+            return *this;
+        }
         move_assign(std::move(other));
         return *this;
     }
 
     VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other)
     {
-        copy_assign(other);
+        if (this != &other)
+            copy_assign(other);
         return *this;
     }
 
@@ -872,51 +831,44 @@ public:
 
     // visitor
     // unary
-    template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
-    auto VARIANT_INLINE static visit(V const& v, F&& f)
-        -> decltype(detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f)))
+    template <typename F, typename V, typename T0 = alternative_ref<V>,
+              typename R = detail::result_of_unary_visit<F, T0>>
+    VARIANT_INLINE static R visit(V&& v, F&& f)
     {
-        return detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
-    }
-    // non-const
-    template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
-    auto VARIANT_INLINE static visit(V& v, F&& f)
-        -> decltype(detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)))
-    {
-        return detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
+        return detail::dispatcher<R, Types...>::apply(std::forward<V>(v), std::forward<F>(f));
     }
 
     // binary
-    // const
-    template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
-    auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f)
-        -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f)))
-    {
-        return detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
-    }
-    // non-const
-    template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
-    auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f)
-        -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f)))
+    template <typename F, typename V, typename T0 = alternative_ref<V>,
+              typename R = detail::result_of_binary_visit<F, T0>>
+    VARIANT_INLINE static R binary_visit(V&& v0, V&& v1, F&& f)
     {
-        return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
+        return detail::binary_dispatcher<R, Types...>::apply(std::forward<V>(v0),
+                                                             std::forward<V>(v1),
+                                                             std::forward<F>(f));
     }
 
     // match
     // unary
     template <typename... Fs>
-    auto VARIANT_INLINE match(Fs&&... fs) const
+    auto VARIANT_INLINE match(Fs&&... fs) const&
         -> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)))
     {
         return variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...));
     }
     // non-const
     template <typename... Fs>
-    auto VARIANT_INLINE match(Fs&&... fs)
+    auto VARIANT_INLINE match(Fs&&... fs) &
         -> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)))
     {
         return variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...));
     }
+    template <typename... Fs>
+    auto VARIANT_INLINE match(Fs&&... fs) &&
+        -> decltype(variant::visit(std::move(*this), ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)))
+    {
+        return variant::visit(std::move(*this), ::mapbox::util::make_visitor(std::forward<Fs>(fs)...));
+    }
 
     ~variant() noexcept // no-throw destructor
     {
@@ -967,33 +919,19 @@ public:
 };
 
 // unary visitor interface
-// const
 template <typename F, typename V>
-auto VARIANT_INLINE apply_visitor(F&& f, V const& v) -> decltype(V::visit(v, std::forward<F>(f)))
+auto VARIANT_INLINE apply_visitor(F&& f, V&& v)
+    -> decltype(v.visit(std::forward<V>(v), std::forward<F>(f)))
 {
-    return V::visit(v, std::forward<F>(f));
-}
-
-// non-const
-template <typename F, typename V>
-auto VARIANT_INLINE apply_visitor(F&& f, V& v) -> decltype(V::visit(v, std::forward<F>(f)))
-{
-    return V::visit(v, std::forward<F>(f));
+    return v.visit(std::forward<V>(v), std::forward<F>(f));
 }
 
 // binary visitor interface
-// const
-template <typename F, typename V>
-auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
-{
-    return V::binary_visit(v0, v1, std::forward<F>(f));
-}
-
-// non-const
 template <typename F, typename V>
-auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
+auto VARIANT_INLINE apply_visitor(F&& f, V&& v0, V&& v1)
+    -> decltype(v0.binary_visit(std::forward<V>(v0), std::forward<V>(v1), std::forward<F>(f)))
 {
-    return V::binary_visit(v0, v1, std::forward<F>(f));
+    return v0.binary_visit(std::forward<V>(v0), std::forward<V>(v1), std::forward<F>(f));
 }
 
 // getter interface


=====================================
test/compilation_failure/get_type.cpp
=====================================
@@ -1,4 +1,4 @@
-// @EXPECTED: enable_if
+// @EXPECTED: no matching .*\<function for call to .*\<get\>
 
 #include <mapbox/variant.hpp>
 


=====================================
test/compilation_failure/mutating_visitor_on_const.cpp
=====================================
@@ -1,4 +1,4 @@
-// @EXPECTED: const int
+// @EXPECTED: no matching function for call to .*\<apply_visitor\>
 
 #include <mapbox/variant.hpp>
 


=====================================
test/lambda_overload_test.cpp
=====================================
@@ -10,6 +10,15 @@
 
 using namespace mapbox::util;
 
+template <typename T>
+struct tag
+{
+    static void dump(const char* prefix)
+    {
+        std::cout << prefix << ": " << typeid(tag<T>).name() << std::endl;
+    }
+};
+
 template <typename Left, typename Right>
 using Either = mapbox::util::variant<Left, Right>;
 
@@ -55,6 +64,37 @@ void test_singleton_variant()
     apply_visitor(make_visitor([](int) {}), singleton);
 }
 
+// See #180
+struct test_call_nonconst_member_visitor
+{
+    template <typename T>
+    void operator() (T & obj) const
+    {
+        tag<decltype(obj)>::dump("test_call_nonconst_member: visitor");
+        obj.foo();
+    }
+};
+
+void test_call_nonconst_member()
+{
+    struct object
+    {
+        void foo() { val = 42;}
+        int val = 0;
+    };
+
+    variant<object> v = object{};
+    apply_visitor(test_call_nonconst_member_visitor{}, v);
+
+#ifdef HAS_CPP14_SUPPORT
+    apply_visitor([](auto& obj)
+                  {
+                      tag<decltype(obj)>::dump("test_call_nonconst_member: lambda");
+                      obj.foo();
+                  }, v);
+#endif
+}
+
 void test_lambda_overloads_sfinae()
 #ifdef HAS_CPP14_SUPPORT
 {
@@ -193,10 +233,41 @@ void test_match_overloads_otherwise()
 }
 #endif
 
+template <typename>
+struct Moveable
+{
+    Moveable() = default; // Default constructible
+
+    Moveable(const Moveable&) = delete;            // Disable copy ctor
+    Moveable& operator=(const Moveable&) = delete; // Disable copy assign op
+
+    Moveable(Moveable&&) = default;            // Enable move ctor
+    Moveable& operator=(Moveable&&) = default; // Enable move assign op
+};
+
+void test_match_move_out_of_variant()
+{
+    // Distinguishable at type level
+    using T1 = Moveable<struct Tag1>;
+    using T2 = Moveable<struct Tag2>;
+    using T3 = mapbox::util::recursive_wrapper<int>;
+
+    mapbox::util::variant<T1, T2> v = T1{};
+
+    std::move(v).match([](T1&&) {},  // Consume T1 by value
+                       [](T2&&) {}); // Consume T2 by value
+
+    mapbox::util::variant<T3, T2> w = T2{};
+
+    std::move(w).match([](int&&) {}, // Consume unwrapped int
+                       [](T2&&) {}); // Consume T2 by value
+}
+
 int main()
 {
     test_lambda_overloads();
     test_singleton_variant();
+    test_call_nonconst_member();
     test_lambda_overloads_capture();
     test_lambda_overloads_sfinae();
 
@@ -205,6 +276,7 @@ int main()
     test_match_overloads_capture();
     test_match_overloads_init_capture();
     test_match_overloads_otherwise();
+    test_match_move_out_of_variant();
 }
 
 #undef HAS_CPP14_SUPPORT


=====================================
test/t/optional.cpp
=====================================
@@ -1,4 +1,3 @@
-
 #include "catch.hpp"
 
 #include <mapbox/optional.hpp>
@@ -97,6 +96,8 @@ TEST_CASE("self assignment", "[optional]")
 
     a = 1;
     REQUIRE(a.get() == 1);
+#if !defined(__clang__)
     a = a;
     REQUIRE(a.get() == 1);
+#endif
 }


=====================================
test/t/visitor_result_type.cpp
=====================================
@@ -0,0 +1,52 @@
+#include <mapbox/variant.hpp>
+
+using namespace mapbox::util;
+
+namespace {
+
+template <typename... T>
+struct tag {};
+
+struct deduced_result_visitor
+{
+    template <typename T>
+    tag<T> operator() (T);
+
+    template <typename T>
+    tag<T const> operator() (T) const;
+
+    template <typename T, typename U>
+    tag<T, U> operator() (T, U);
+
+    template <typename T, typename U>
+    tag<T, U const> operator() (T, U) const;
+};
+
+struct explicit_result_visitor : deduced_result_visitor
+{
+    using result_type = tag<float>;
+};
+
+// Doing this compile-time test via assignment to typed tag objects gives
+// more useful error messages when something goes wrong, than std::is_same
+// in a static_assert would. Here if result_of_unary_visit returns anything
+// other than the expected type on the left hand side, the conversion error
+// message will tell you exactly what it was.
+
+#ifdef __clang__
+# pragma clang diagnostic ignored "-Wunused-variable"
+#endif
+
+tag<int> d1m = detail::result_of_unary_visit<deduced_result_visitor, int>{};
+tag<int const> d1c = detail::result_of_unary_visit<deduced_result_visitor const, int>{};
+
+tag<float> e1m = detail::result_of_unary_visit<explicit_result_visitor, int>{};
+tag<float> e1c = detail::result_of_unary_visit<explicit_result_visitor const, int>{};
+
+tag<int, int> d2m = detail::result_of_binary_visit<deduced_result_visitor, int>{};
+tag<int, int const> d2c = detail::result_of_binary_visit<deduced_result_visitor const, int>{};
+
+tag<float> e2m = detail::result_of_binary_visit<explicit_result_visitor, int>{};
+tag<float> e2c = detail::result_of_binary_visit<explicit_result_visitor const, int>{};
+
+} // namespace



View it on GitLab: https://salsa.debian.org/debian-gis-team/mapbox-variant/-/commit/d010b70ef4a43edfaee4eaeb8d89114f4ef118cc

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/mapbox-variant/-/commit/d010b70ef4a43edfaee4eaeb8d89114f4ef118cc
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20200803/0317be64/attachment-0001.html>


More information about the Pkg-grass-devel mailing list