Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions test/t/unary_visitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,25 @@ TEST_CASE("changes in const visitor (with mutable internals) should be visible",
REQUIRE(mapbox::util::apply_visitor(ts, v) == sizeof(std::string));
REQUIRE(ts.result() == sizeof(std::string));
}

struct is_uninitialized_visitor
{
bool operator() () const { return true; }

template <typename T>
bool operator() (T const& ) const { return false; }
};

TEST_CASE("apply_visitor on uninitialized variant", "[visitor][unary visitor]")
{
namespace mu = mapbox::util;
using variant_type = mu::variant<int, std::string, double>;
variant_type v{mu::no_init()};

// total_sizeof doesn't have operator()()
CHECK_THROWS_AS(mu::apply_visitor(total_sizeof(), v), mu::bad_variant_access);

// is_uninitialied_visitor has operator()()
REQUIRE_NOTHROW(mu::apply_visitor(is_uninitialized_visitor(), v));
CHECK(mu::apply_visitor(is_uninitialized_visitor(), v) == true);
}
38 changes: 28 additions & 10 deletions variant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ class bad_variant_access : public std::runtime_error

}; // class bad_variant_access

struct no_init
{
};

template <typename R = void>
struct MAPBOX_VARIANT_DEPRECATED static_visitor
{
Expand Down Expand Up @@ -289,6 +293,24 @@ struct unwrapper<std::reference_wrapper<T>>
}
};

template <typename R, typename F, typename Enable = void>
struct dispatch_no_init
{
VARIANT_INLINE static R apply(F&&)
{
throw bad_variant_access("apply_visitor on uninitialized variant");
}
};

template <typename R, typename F>
struct dispatch_no_init<R, F, decltype(void(std::declval<F>()()))>
{
VARIANT_INLINE static R apply(F&& f)
{
return f();
}
};

template <typename F, typename V, typename R, typename... Types>
struct dispatcher;

Expand Down Expand Up @@ -320,17 +342,17 @@ struct dispatcher<F, V, R, T, Types...>
}
};

template <typename F, typename V, typename R, typename T>
struct dispatcher<F, V, R, T>
template <typename F, typename V, typename R>
struct dispatcher<F, V, R>
{
VARIANT_INLINE static R apply_const(V const& v, F&& f)
VARIANT_INLINE static R apply_const(V const&, F&& f)
{
return f(unwrapper<T>::apply_const(v.template get<T>()));
return dispatch_no_init<R, F>::apply(std::forward<F>(f));
}

VARIANT_INLINE static R apply(V& v, F&& f)
VARIANT_INLINE static R apply(V&, F&& f)
{
return f(unwrapper<T>::apply(v.template get<T>()));
return dispatch_no_init<R, F>::apply(std::forward<F>(f));
}
};

Expand Down Expand Up @@ -551,10 +573,6 @@ struct static_none_of : std::is_same<std::tuple<std::false_type, typename Predic

} // namespace detail

struct no_init
{
};

template <typename... Types>
class variant
{
Expand Down