#include #include #include #include #if __cplusplus >= 201402L #define HAS_CPP14_SUPPORT #endif using namespace mapbox::util; template struct tag { static void dump(const char* prefix) { std::cout << prefix << ": " << typeid(tag).name() << std::endl; } }; template using Either = mapbox::util::variant; struct Response { }; struct Error { }; void test_lambda_overloads() { Either rv; rv = Response{}; auto visitor = make_visitor([](Response) { std::cout << "Response\n"; }, // [](Error) { std::cout << "Error\n"; }); // apply_visitor(visitor, rv); } void test_lambda_overloads_capture() { Either rv; rv = Error{}; int ok = 0; int err = 0; auto visitor = make_visitor([&](Response) { ok += 1; }, // [&](Error) { err += 1; }); // apply_visitor(visitor, rv); std::cout << "Got " << ok << " ok, " << err << " err" << std::endl; } void test_singleton_variant() { variant singleton; apply_visitor(make_visitor([](int) {}), singleton); } // See #180 struct test_call_nonconst_member_visitor { template void operator() (T & obj) const { tag::dump("test_call_nonconst_member: visitor"); obj.foo(); } }; void test_call_nonconst_member() { struct object { void foo() { val = 42;} int val = 0; }; variant v = object{}; apply_visitor(test_call_nonconst_member_visitor{}, v); #ifdef HAS_CPP14_SUPPORT apply_visitor([](auto& obj) { tag::dump("test_call_nonconst_member: lambda"); obj.foo(); }, v); #endif } void test_lambda_overloads_sfinae() #ifdef HAS_CPP14_SUPPORT { variant> var; auto visitor = make_visitor([](auto range) -> decltype(std::begin(range), void()) { for (auto each : range) std::cout << each << ' '; }, [](auto x) -> decltype(std::cout << x, void()) { std::cout << x << std::endl; }); var = 1; apply_visitor(visitor, var); var = 2.f; apply_visitor(visitor, var); var = std::vector{4, 5, 6}; apply_visitor(visitor, var); } #else { } #endif void test_match_singleton() { variant singleton = 5; singleton.match([](int) {}); auto lambda = [](int) {}; singleton.match(lambda); } void test_match_overloads() { Either rv; rv = Response{}; rv.match([](Response) { std::cout << "Response\n"; }, // [](Error) { std::cout << "Error\n"; }); // } void test_match_overloads_capture() { Either rv; rv = Error{}; int ok = 0; int err = 0; rv.match([&](Response) { ok += 1; }, // [&](Error) { err += 1; }); // std::cout << "Got " << ok << " ok, " << err << " err" << std::endl; } struct MovableOnly { MovableOnly() = default; MovableOnly(MovableOnly&&) = default; MovableOnly& operator=(MovableOnly&&) = default; }; struct MovableCopyable { MovableCopyable() = default; MovableCopyable(MovableCopyable&&) = default; MovableCopyable& operator=(MovableCopyable&&) = default; MovableCopyable(const MovableCopyable&) = default; MovableCopyable& operator=(const MovableCopyable&) = default; }; void test_match_overloads_init_capture() #ifdef HAS_CPP14_SUPPORT { Either 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 { struct Center { }; struct Indent { }; struct Justify { }; struct None { }; using Properties = mapbox::util::variant; Properties props = Justify{}; props.match([&](Center) { std::cout << "Center\n"; }, // [&](Indent) { std::cout << "Indent\n"; }, // [&](auto&&) { std::cout << "Otherwise\n"; }); // } #else { } #endif template 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; using T2 = Moveable; using T3 = mapbox::util::recursive_wrapper; mapbox::util::variant v = T1{}; std::move(v).match([](T1&&) {}, // Consume T1 by value [](T2&&) {}); // Consume T2 by value mapbox::util::variant 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(); test_match_singleton(); test_match_overloads(); test_match_overloads_capture(); test_match_overloads_init_capture(); test_match_overloads_otherwise(); test_match_move_out_of_variant(); } #undef HAS_CPP14_SUPPORT