// { dg-options "-std=gnu++17" } // { dg-do run } // Copyright (C) 2016-2018 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License along // with this library; see the file COPYING3. If not see // . #include #include #include #include #include using namespace std; struct AlwaysThrow { AlwaysThrow() = default; AlwaysThrow(const AlwaysThrow&) { throw nullptr; } AlwaysThrow(AlwaysThrow&&) { throw nullptr; } AlwaysThrow& operator=(const AlwaysThrow&) { throw nullptr; return *this; } AlwaysThrow& operator=(AlwaysThrow&&) { throw nullptr; return *this; } bool operator<(const AlwaysThrow&) const { VERIFY(false); } bool operator<=(const AlwaysThrow&) const { VERIFY(false); } bool operator==(const AlwaysThrow&) const { VERIFY(false); } bool operator!=(const AlwaysThrow&) const { VERIFY(false); } bool operator>=(const AlwaysThrow&) const { VERIFY(false); } bool operator>(const AlwaysThrow&) const { VERIFY(false); } }; void default_ctor() { variant v; VERIFY(holds_alternative(v)); } void copy_ctor() { variant v("a"); VERIFY(holds_alternative(v)); variant u(v); VERIFY(holds_alternative(u)); VERIFY(get(u) == "a"); } void move_ctor() { variant v("a"); VERIFY(holds_alternative(v)); variant u(std::move(v)); VERIFY(holds_alternative(u)); VERIFY(get(u) == "a"); VERIFY(holds_alternative(v)); } void arbitrary_ctor() { variant v("a"); VERIFY(holds_alternative(v)); VERIFY(get<1>(v) == "a"); } void copy_assign() { variant v("a"); VERIFY(holds_alternative(v)); variant u; u = v; VERIFY(holds_alternative(u)); VERIFY(get(u) == "a"); } void move_assign() { variant v("a"); VERIFY(holds_alternative(v)); variant u; u = std::move(v); VERIFY(holds_alternative(u)); VERIFY(get(u) == "a"); VERIFY(holds_alternative(v)); } void arbitrary_assign() { variant v; v = "a"; VERIFY(holds_alternative(variant("a"))); VERIFY(get<1>(v) == "a"); } void dtor() { struct A { A(int& called) : called(called) {} ~A() { called++; } int& called; }; { int called = 0; { variant a(in_place_index<1>, called); } VERIFY(called == 1); } { int called = 0; { variant a(in_place_index<0>); } VERIFY(called == 0); } } void in_place_index_ctor() { { variant v(in_place_index<1>, "a"); VERIFY(holds_alternative(v)); VERIFY(get<1>(v) == "a"); } { variant v(in_place_index<1>, {'a', 'b'}); VERIFY(holds_alternative(v)); VERIFY(get<1>(v) == "ab"); } } void in_place_type_ctor() { { variant v(in_place_type, "a"); VERIFY(holds_alternative(v)); VERIFY(get<1>(v) == "a"); } { variant v(in_place_type, {'a', 'b'}); VERIFY(holds_alternative(v)); VERIFY(get<1>(v) == "ab"); } } void emplace() { variant v; v.emplace<0>(1); VERIFY(get<0>(v) == 1); v.emplace("a"); VERIFY(get(v) == "a"); v.emplace<1>({'a', 'b'}); VERIFY(get<1>(v) == "ab"); v.emplace({'a', 'c'}); VERIFY(get(v) == "ac"); { variant v; AlwaysThrow a; try { v.emplace<1>(a); } catch (nullptr_t) { } VERIFY(v.valueless_by_exception()); } { variant v; try { v.emplace<1>(AlwaysThrow{}); } catch (nullptr_t) { } VERIFY(v.valueless_by_exception()); } VERIFY(&v.emplace<0>(1) == &std::get<0>(v)); VERIFY(&v.emplace(1) == &std::get(v)); VERIFY(&v.emplace<1>("a") == &std::get<1>(v)); VERIFY(&v.emplace("a") == &std::get(v)); { variant> v; VERIFY(&v.emplace<0>({1,2,3}) == &std::get<0>(v)); VERIFY(&v.emplace>({1,2,3}) == &std::get>(v)); } } void test_get() { VERIFY(get<1>(variant("a")) == "a"); VERIFY(get(variant("a")) == "a"); { bool caught = false; try { get<0>(variant("a")); } catch (const bad_variant_access&) { caught = true; } VERIFY(caught); } { bool caught = false; try { get(variant("a")); } catch (const bad_variant_access&) { caught = true; } VERIFY(caught); } } void test_relational() { VERIFY((variant(2) < variant(3))); VERIFY((variant(3) == variant(3))); VERIFY((variant(3) > variant(2))); VERIFY((variant(3) <= variant(3))); VERIFY((variant(2) <= variant(3))); VERIFY((variant(3) >= variant(3))); VERIFY((variant(3) >= variant(2))); VERIFY((variant(2) != variant(3))); VERIFY((variant(2) < variant("a"))); VERIFY((variant(2) > variant("a"))); { variant v, w; try { AlwaysThrow a; v = a; } catch (nullptr_t) { } VERIFY(v.valueless_by_exception()); VERIFY(v < w); VERIFY(v <= w); VERIFY(!(v == w)); VERIFY(v != w); VERIFY(w > v); VERIFY(w >= v); } } void test_swap() { variant a("a"), b("b"); a.swap(b); VERIFY(get<1>(a) == "b"); VERIFY(get<1>(b) == "a"); swap(a, b); VERIFY(get<1>(a) == "a"); VERIFY(get<1>(b) == "b"); } void test_visit() { { struct Visitor { int operator()(int, float) { return 0; } int operator()(int, double) { return 1; } int operator()(char, float) { return 2; } int operator()(char, double) { return 3; } int operator()(int, float) const { return 5; } int operator()(int, double) const { return 6; } int operator()(char, float) const { return 7; } int operator()(char, double) const { return 8; } } visitor1; VERIFY(visit(visitor1, variant(1), variant(1.0f)) == 0); VERIFY(visit(visitor1, variant(1), variant(1.0)) == 1); VERIFY(visit(visitor1, variant('a'), variant(1.0f)) == 2); VERIFY(visit(visitor1, variant('a'), variant(1.0)) == 3); const auto& visitor2 = visitor1; VERIFY(visit(visitor2, variant(1), variant(1.0f)) == 5); VERIFY(visit(visitor2, variant(1), variant(1.0)) == 6); VERIFY(visit(visitor2, variant('a'), variant(1.0f)) == 7); VERIFY(visit(visitor2, variant('a'), variant(1.0)) == 8); } { struct Visitor { int operator()(int, float) && { return 0; } int operator()(int, double) && { return 1; } int operator()(char, float) && { return 2; } int operator()(char, double) && { return 3; } }; VERIFY(visit(Visitor{}, variant(1), variant(1.0f)) == 0); VERIFY(visit(Visitor{}, variant(1), variant(1.0)) == 1); VERIFY(visit(Visitor{}, variant('a'), variant(1.0f)) == 2); VERIFY(visit(Visitor{}, variant('a'), variant(1.0)) == 3); } } void test_hash() { unordered_set> s; VERIFY(s.emplace(3).second); VERIFY(s.emplace("asdf").second); VERIFY(s.emplace().second); VERIFY(s.size() == 3); VERIFY(!s.emplace(3).second); VERIFY(!s.emplace("asdf").second); VERIFY(!s.emplace().second); VERIFY(s.size() == 3); { struct A { operator int() { throw nullptr; } }; variant v; try { v.emplace<0>(A{}); } catch (nullptr_t) { } VERIFY(v.valueless_by_exception()); VERIFY(s.insert(v).second); VERIFY(s.size() == 4); VERIFY(!s.insert(v).second); } } void test_valueless_by_exception() { { AlwaysThrow a; bool caught = false; try { variant v(a); } catch (nullptr_t) { caught = true; } VERIFY(caught); } { AlwaysThrow a; bool caught = false; try { variant v(a); } catch (nullptr_t) { caught = true; } VERIFY(caught); } { variant v; bool caught = false; try { AlwaysThrow a; v = a; } catch (nullptr_t) { caught = true; } VERIFY(caught); VERIFY(v.valueless_by_exception()); } { variant v; bool caught = false; try { v = AlwaysThrow{}; } catch (nullptr_t) { caught = true; } VERIFY(caught); VERIFY(v.valueless_by_exception()); } } int main() { default_ctor(); copy_ctor(); move_ctor(); arbitrary_ctor(); in_place_index_ctor(); in_place_type_ctor(); copy_assign(); move_assign(); arbitrary_assign(); dtor(); emplace(); test_get(); test_relational(); test_swap(); test_visit(); test_hash(); test_valueless_by_exception(); }