Skip to content

Commit

Permalink
Use forwarding reference in make_visitor and visitor
Browse files Browse the repository at this point in the history
It avoids internal copies of closures passed to make_visitor and it
permits the usage of init capture(feature of C++14) to use movable
only types.

 - Add test case for lambda with init capture and movable(but not
   copyable) object
 - Add test case for match() receiving a lvalue reference to a lambda.
  • Loading branch information
ricardocosme committed Jun 27, 2017
1 parent 266f68d commit 9f991da
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 7 deletions.
19 changes: 12 additions & 7 deletions include/mapbox/variant_visitor.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef MAPBOX_UTIL_VARIANT_VISITOR_HPP
#define MAPBOX_UTIL_VARIANT_VISITOR_HPP

#include <utility>

namespace mapbox {
namespace util {

Expand All @@ -10,28 +12,31 @@ struct visitor;
template <typename Fn>
struct visitor<Fn> : Fn
{
using type = Fn;
using Fn::operator();

visitor(Fn fn) : Fn(fn) {}
template<typename T>
visitor(T&& fn) : Fn(std::forward<T>(fn)) {}
};

template <typename Fn, typename... Fns>
struct visitor<Fn, Fns...> : Fn, visitor<Fns...>
{
using type = visitor;
using Fn::operator();
using visitor<Fns...>::operator();

visitor(Fn fn, Fns... fns) : Fn(fn), visitor<Fns...>(fns...) {}
template<typename T, typename... Ts>
visitor(T&& fn, Ts&&... fns)
: Fn(std::forward<T>(fn))
, visitor<Fns...>(std::forward<Ts>(fns)...) {}
};

template <typename... Fns>
visitor<Fns...> make_visitor(Fns... fns)
visitor<typename std::decay<Fns>::type...> make_visitor(Fns&&... fns)
{
return visitor<Fns...>(fns...);
return visitor<typename std::decay<Fns>::type...>
(std::forward<Fns>(fns)...);
}

} // namespace util
} // namespace mapbox

Expand Down
45 changes: 45 additions & 0 deletions test/lambda_overload_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ void test_match_singleton()
{
variant<int> singleton = 5;
singleton.match([](int) {});

auto lambda = [](int) {};
singleton.match(lambda);
}

void test_match_overloads()
Expand Down Expand Up @@ -112,6 +115,47 @@ void test_match_overloads_capture()
std::cout << "Got " << ok << " ok, " << err << " err" << std::endl;
}

struct MovableOnly
{
MovableOnly() = default;
MovableOnly(MovableOnly&&) = default;
};

struct MovableCopyable
{
MovableCopyable() = default;
MovableCopyable(MovableCopyable&&) = default;
MovableCopyable(const MovableCopyable&) = default;
};

void test_match_overloads_init_capture()
#ifdef HAS_CPP14_SUPPORT
{
Either<Error, Response> rv;

rv = Error{};

rv.match([p = MovableOnly{}](auto&&) {});
{
auto lambda = [p = MovableCopyable{}](auto&&) {};
rv.match(lambda);

rv.match([p = MovableOnly{}](Response) { std::cout << "Response\n"; },
[p = MovableOnly{}](Error) { std::cout << "Error\n"; });
}
{
auto lambda = [](Error) { std::cout << "Error\n"; };
rv.match([p = MovableOnly{}](Response) { std::cout << "Response\n"; },
lambda);
rv.match(lambda,
[p = MovableOnly{}](Response) { std::cout << "Response\n"; });
}
}
#else
{
}
#endif

// See #140
void test_match_overloads_otherwise()
#ifdef HAS_CPP14_SUPPORT
Expand Down Expand Up @@ -153,6 +197,7 @@ int main()
test_match_singleton();
test_match_overloads();
test_match_overloads_capture();
test_match_overloads_init_capture();
test_match_overloads_otherwise();
}

Expand Down

0 comments on commit 9f991da

Please sign in to comment.