[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