| // -*- C++ -*- |
| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // UNSUPPORTED: c++98, c++03, c++11, c++14 |
| |
| // XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions |
| |
| // <variant> |
| |
| // template <class ...Types> class variant; |
| |
| // template <class T, class ...Args> T& emplace(Args&&... args); |
| |
| #include <cassert> |
| #include <string> |
| #include <type_traits> |
| #include <variant> |
| |
| #include "archetypes.h" |
| #include "test_convertible.h" |
| #include "test_macros.h" |
| #include "variant_test_helpers.h" |
| |
| template <class Var, class T, class... Args> |
| constexpr auto test_emplace_exists_imp(int) -> decltype( |
| std::declval<Var>().template emplace<T>(std::declval<Args>()...), true) { |
| return true; |
| } |
| |
| template <class, class, class...> |
| constexpr auto test_emplace_exists_imp(long) -> bool { |
| return false; |
| } |
| |
| template <class... Args> constexpr bool emplace_exists() { |
| return test_emplace_exists_imp<Args...>(0); |
| } |
| |
| void test_emplace_sfinae() { |
| { |
| using V = std::variant<int, void *, const void *, TestTypes::NoCtors>; |
| static_assert(emplace_exists<V, int>(), ""); |
| static_assert(emplace_exists<V, int, int>(), ""); |
| static_assert(!emplace_exists<V, int, decltype(nullptr)>(), |
| "cannot construct"); |
| static_assert(emplace_exists<V, void *, decltype(nullptr)>(), ""); |
| static_assert(!emplace_exists<V, void *, int>(), "cannot construct"); |
| static_assert(emplace_exists<V, void *, int *>(), ""); |
| static_assert(!emplace_exists<V, void *, const int *>(), ""); |
| static_assert(emplace_exists<V, const void *, const int *>(), ""); |
| static_assert(emplace_exists<V, const void *, int *>(), ""); |
| static_assert(!emplace_exists<V, TestTypes::NoCtors>(), "cannot construct"); |
| } |
| #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) |
| using V = std::variant<int, int &, const int &, int &&, long, long, |
| TestTypes::NoCtors>; |
| static_assert(emplace_exists<V, int>(), ""); |
| static_assert(emplace_exists<V, int, int>(), ""); |
| static_assert(emplace_exists<V, int, long long>(), ""); |
| static_assert(!emplace_exists<V, int, int, int>(), "too many args"); |
| static_assert(emplace_exists<V, int &, int &>(), ""); |
| static_assert(!emplace_exists<V, int &>(), "cannot default construct ref"); |
| static_assert(!emplace_exists<V, int &, const int &>(), "cannot bind ref"); |
| static_assert(!emplace_exists<V, int &, int &&>(), "cannot bind ref"); |
| static_assert(emplace_exists<V, const int &, int &>(), ""); |
| static_assert(emplace_exists<V, const int &, const int &>(), ""); |
| static_assert(emplace_exists<V, const int &, int &&>(), ""); |
| static_assert(!emplace_exists<V, const int &, void *>(), |
| "not constructible from void*"); |
| static_assert(emplace_exists<V, int &&, int>(), ""); |
| static_assert(!emplace_exists<V, int &&, int &>(), "cannot bind ref"); |
| static_assert(!emplace_exists<V, int &&, const int &>(), "cannot bind ref"); |
| static_assert(!emplace_exists<V, int &&, const int &&>(), "cannot bind ref"); |
| static_assert(!emplace_exists<V, long, long>(), "ambiguous"); |
| static_assert(!emplace_exists<V, TestTypes::NoCtors>(), |
| "cannot construct void"); |
| #endif |
| } |
| |
| void test_basic() { |
| { |
| using V = std::variant<int>; |
| V v(42); |
| auto& ref1 = v.emplace<int>(); |
| static_assert(std::is_same_v<int&, decltype(ref1)>, ""); |
| assert(std::get<0>(v) == 0); |
| assert(&ref1 == &std::get<0>(v)); |
| auto& ref2 = v.emplace<int>(42); |
| static_assert(std::is_same_v<int&, decltype(ref2)>, ""); |
| assert(std::get<0>(v) == 42); |
| assert(&ref2 == &std::get<0>(v)); |
| } |
| { |
| using V = |
| std::variant<int, long, const void *, TestTypes::NoCtors, std::string>; |
| const int x = 100; |
| V v(std::in_place_type<int>, -1); |
| // default emplace a value |
| auto& ref1 = v.emplace<long>(); |
| static_assert(std::is_same_v<long&, decltype(ref1)>, ""); |
| assert(std::get<1>(v) == 0); |
| assert(&ref1 == &std::get<1>(v)); |
| auto& ref2 = v.emplace<const void *>(&x); |
| static_assert(std::is_same_v<const void *&, decltype(ref2)>, ""); |
| assert(std::get<2>(v) == &x); |
| assert(&ref2 == &std::get<2>(v)); |
| // emplace with multiple args |
| auto& ref3 = v.emplace<std::string>(3u, 'a'); |
| static_assert(std::is_same_v<std::string&, decltype(ref3)>, ""); |
| assert(std::get<4>(v) == "aaa"); |
| assert(&ref3 == &std::get<4>(v)); |
| } |
| #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) |
| { |
| using V = std::variant<int, long, const int &, int &&, TestTypes::NoCtors, |
| std::string>; |
| const int x = 100; |
| int y = 42; |
| int z = 43; |
| V v(std::in_place_index<0>, -1); |
| // default emplace a value |
| auto& ref1 = v.emplace<long>(); |
| static_assert(std::is_same_v<long&, decltype(ref1)>, ""); |
| assert(std::get<long>(v) == 0); |
| assert(&ref1 == &std::get<long>(v)); |
| // emplace a reference |
| auto& ref2 = v.emplace<const int &>(x); |
| static_assert(std::is_same_v<const int&, decltype(ref2)>, ""); |
| assert(&std::get<const int &>(v) == &x); |
| assert(&ref2 == &std::get<const int &>(v)); |
| // emplace an rvalue reference |
| auto& ref3 = v.emplace<int &&>(std::move(y)); |
| static_assert(std::is_same_v<int &&, decltype(ref3)>, ""); |
| assert(&std::get<int &&>(v) == &y); |
| assert(&ref3 == &std::get<int &&>(v)); |
| // re-emplace a new reference over the active member |
| auto& ref4 = v.emplace<int &&>(std::move(z)); |
| static_assert(std::is_same_v<int &, decltype(ref4)>, ""); |
| assert(&std::get<int &&>(v) == &z); |
| assert(&ref4 == &std::get<int &&>(v)); |
| // emplace with multiple args |
| auto& ref5 = v.emplace<std::string>(3u, 'a'); |
| static_assert(std::is_same_v<std::string&, decltype(ref5)>, ""); |
| assert(std::get<std::string>(v) == "aaa"); |
| assert(&ref5 == &std::get<std::string>(v)); |
| } |
| #endif |
| } |
| |
| int main(int, char**) { |
| test_basic(); |
| test_emplace_sfinae(); |
| |
| return 0; |
| } |