From 98d9a858da5c08085eeec92f7edabd2555225ef2 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Sat, 15 Apr 2017 19:32:02 +0000 Subject: [PATCH] Implement LWG 2857 for variant. Tests from Casey Carter @ Microsoft. Also mark LWG 2857 as complete, since the changes to optional and any were completed by Marshall earlier. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@300403 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/variant | 34 ++++++++------- .../variant.mod/emplace_index_args.pass.cpp | 43 ++++++++++++++----- .../emplace_index_init_list_args.pass.cpp | 14 ++++-- .../variant.mod/emplace_type_args.pass.cpp | 42 +++++++++++++----- .../emplace_type_init_list_args.pass.cpp | 14 ++++-- www/cxx1z_status.html | 2 +- 6 files changed, 102 insertions(+), 47 deletions(-) diff --git a/include/variant b/include/variant index 33f88e057..88f7b240d 100644 --- a/include/variant +++ b/include/variant @@ -53,16 +53,16 @@ namespace std { // 20.7.2.4, modifiers template - void emplace(Args&&...); + T& emplace(Args&&...); template - void emplace(initializer_list, Args&&...); + T& emplace(initializer_list, Args&&...); template - void emplace(Args&&...); + variant_alternative_t& emplace(Args&&...); template - void emplace(initializer_list, Args&&...); + variant_alternative_t& emplace(initializer_list, Args&&...); // 20.7.2.5, value status constexpr bool valueless_by_exception() const noexcept; @@ -764,9 +764,10 @@ public: protected: template inline _LIBCPP_INLINE_VISIBILITY - static void __construct_alt(__alt<_Ip, _Tp>& __a, _Args&&... __args) { - ::new (_VSTD::addressof(__a)) + static _Tp& __construct_alt(__alt<_Ip, _Tp>& __a, _Args&&... __args) { + ::new ((void*)_VSTD::addressof(__a)) __alt<_Ip, _Tp>(in_place, _VSTD::forward<_Args>(__args)...); + return __a.__value; } template @@ -876,11 +877,12 @@ public: template inline _LIBCPP_INLINE_VISIBILITY - void __emplace(_Args&&... __args) { + auto& __emplace(_Args&&... __args) { this->__destroy(); - this->__construct_alt(__access::__base::__get_alt<_Ip>(*this), + auto& __res = this->__construct_alt(__access::__base::__get_alt<_Ip>(*this), _VSTD::forward<_Args>(__args)...); this->__index = _Ip; + return __res; } protected: @@ -1218,8 +1220,8 @@ public: class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, enable_if_t, int> = 0> inline _LIBCPP_INLINE_VISIBILITY - void emplace(_Args&&... __args) { - __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...); + _Tp& emplace(_Args&&... __args) { + return __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...); } template < @@ -1231,8 +1233,8 @@ public: enable_if_t&, _Args...>, int> = 0> inline _LIBCPP_INLINE_VISIBILITY - void emplace(initializer_list<_Up> __il, _Args&&... __args) { - __impl.template __emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...); + _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) { + return __impl.template __emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...); } template < @@ -1242,8 +1244,8 @@ public: __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, enable_if_t, int> = 0> inline _LIBCPP_INLINE_VISIBILITY - void emplace(_Args&&... __args) { - __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...); + _Tp& emplace(_Args&&... __args) { + return __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...); } template < @@ -1255,8 +1257,8 @@ public: enable_if_t&, _Args...>, int> = 0> inline _LIBCPP_INLINE_VISIBILITY - void emplace(initializer_list<_Up> __il, _Args&&... __args) { - __impl.template __emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...); + _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) { + return __impl.template __emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...); } inline _LIBCPP_INLINE_VISIBILITY diff --git a/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp b/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp index 8f694cfd5..0d0b978e3 100644 --- a/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp @@ -14,7 +14,8 @@ // template class variant; -// template void emplace(Args&&... args); +// template +// variant_alternative_t>& emplace(Args&&... args); #include #include @@ -85,10 +86,14 @@ void test_basic() { { using V = std::variant; V v(42); - v.emplace<0>(); + auto& ref1 = v.emplace<0>(); + static_assert(std::is_same_v, ""); assert(std::get<0>(v) == 0); - v.emplace<0>(42); + assert(&ref1 == &std::get<0>(v)); + auto& ref2 = v.emplace<0>(42); + static_assert(std::is_same_v, ""); assert(std::get<0>(v) == 42); + assert(&ref2 == &std::get<0>(v)); } { using V = @@ -96,13 +101,19 @@ void test_basic() { const int x = 100; V v(std::in_place_index<0>, -1); // default emplace a value - v.emplace<1>(); + auto& ref1 = v.emplace<1>(); + static_assert(std::is_same_v, ""); assert(std::get<1>(v) == 0); - v.emplace<2>(&x); + assert(&ref1 == &std::get<1>(v)); + auto& ref2 = v.emplace<2>(&x); + static_assert(std::is_same_v, ""); assert(std::get<2>(v) == &x); + assert(&ref2 == &std::get<2>(v)); // emplace with multiple args - v.emplace<4>(3, 'a'); + auto& ref3 = v.emplace<4>(3, 'a'); + static_assert(std::is_same_v, ""); assert(std::get<4>(v) == "aaa"); + assert(&ref3 == &std::get<4>(v)); } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { @@ -113,20 +124,30 @@ void test_basic() { int z = 43; V v(std::in_place_index<0>, -1); // default emplace a value - v.emplace<1>(); + auto& ref1 = v.emplace<1>(); + static_assert(std::is_same_v, ""); assert(std::get<1>(v) == 0); + assert(&ref1 == &std::get<1>(v)); // emplace a reference - v.emplace<2>(x); + auto& ref2 = v.emplace<2>(x); + static_assert(std::is_same_v<&, decltype(ref)>, ""); assert(&std::get<2>(v) == &x); + assert(&ref2 == &std::get<2>(v)); // emplace an rvalue reference - v.emplace<3>(std::move(y)); + auto& ref3 = v.emplace<3>(std::move(y)); + static_assert(std::is_same_v<&, decltype(ref)>, ""); assert(&std::get<3>(v) == &y); + assert(&ref3 == &std::get<3>(v)); // re-emplace a new reference over the active member - v.emplace<3>(std::move(z)); + auto& ref4 = v.emplace<3>(std::move(z)); + static_assert(std::is_same_v<&, decltype(ref)>, ""); assert(&std::get<3>(v) == &z); + assert(&ref4 == &std::get<3>(v)); // emplace with multiple args - v.emplace<5>(3, 'a'); + auto& ref5 = v.emplace<5>(3, 'a'); + static_assert(std::is_same_v, ""); assert(std::get<5>(v) == "aaa"); + assert(&ref5 == &std::get<5>(v)); } #endif } diff --git a/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp b/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp index f466b160c..e69988a08 100644 --- a/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp @@ -15,7 +15,7 @@ // template class variant; // template -// void emplace(initializer_list il,Args&&... args); +// variant_alternative_t>& emplace(initializer_list il,Args&&... args); #include #include @@ -70,13 +70,19 @@ void test_emplace_sfinae() { void test_basic() { using V = std::variant; V v; - v.emplace<1>({1, 2, 3}); + auto& ref1 = v.emplace<1>({1, 2, 3}); + static_assert(std::is_same_v, ""); assert(std::get<1>(v).size == 3); - v.emplace<2>({1, 2, 3, 4}, 42); + assert(&ref1 == &std::get<1>(v)); + auto& ref2 = v.emplace<2>({1, 2, 3, 4}, 42); + static_assert(std::is_same_v, ""); assert(std::get<2>(v).size == 4); assert(std::get<2>(v).value == 42); - v.emplace<1>({1}); + assert(&ref2 == &std::get<2>(v)); + auto& ref3 = v.emplace<1>({1}); + static_assert(std::is_same_v, ""); assert(std::get<1>(v).size == 1); + assert(&ref3 == &std::get<1>(v)); } int main() { diff --git a/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp b/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp index 4ca2cc480..8e329024b 100644 --- a/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp @@ -14,7 +14,7 @@ // template class variant; -// template void emplace(Args&&... args); +// template T& emplace(Args&&... args); #include #include @@ -86,10 +86,14 @@ void test_basic() { { using V = std::variant; V v(42); - v.emplace(); + auto& ref1 = v.emplace(); + static_assert(std::is_same_v, ""); assert(std::get<0>(v) == 0); - v.emplace(42); + assert(&ref1 == &std::get<0>(v)); + auto& ref2 = v.emplace(42); + static_assert(std::is_same_v, ""); assert(std::get<0>(v) == 42); + assert(&ref2 == &std::get<0>(v)); } { using V = @@ -97,13 +101,19 @@ void test_basic() { const int x = 100; V v(std::in_place_type, -1); // default emplace a value - v.emplace(); + auto& ref1 = v.emplace(); + static_assert(std::is_same_v, ""); assert(std::get<1>(v) == 0); - v.emplace(&x); + assert(&ref1 == &std::get<1>(v)); + auto& ref2 = v.emplace(&x); + static_assert(std::is_same_v, ""); assert(std::get<2>(v) == &x); + assert(&ref2 == &std::get<2>(v)); // emplace with multiple args - v.emplace(3, 'a'); + auto& ref3 = v.emplace(3, 'a'); + static_assert(std::is_same_v, ""); assert(std::get<4>(v) == "aaa"); + assert(&ref3 == &std::get<4>(v)); } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { @@ -114,20 +124,30 @@ void test_basic() { int z = 43; V v(std::in_place_index<0>, -1); // default emplace a value - v.emplace(); + auto& ref1 = v.emplace(); + static_assert(std::is_same_v, ""); assert(std::get(v) == 0); + assert(&ref1 == &std::get(v)); // emplace a reference - v.emplace(x); + auto& ref2 = v.emplace(x); + static_assert(std::is_same_v, ""); assert(&std::get(v) == &x); + assert(&ref2 == &std::get(v)); // emplace an rvalue reference - v.emplace(std::move(y)); + auto& ref3 = v.emplace(std::move(y)); + static_assert(std::is_same_v, ""); assert(&std::get(v) == &y); + assert(&ref3 == &std::get(v)); // re-emplace a new reference over the active member - v.emplace(std::move(z)); + auto& ref4 = v.emplace(std::move(z)); + static_assert(std::is_same_v, ""); assert(&std::get(v) == &z); + assert(&ref4 == &std::get(v)); // emplace with multiple args - v.emplace(3, 'a'); + auto& ref5 = v.emplace(3, 'a'); + static_assert(std::is_same_v, ""); assert(std::get(v) == "aaa"); + assert(&ref5 == &std::get(v)); } #endif } diff --git a/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp b/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp index b2be8ac5b..da1658cb8 100644 --- a/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp +++ b/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp @@ -15,7 +15,7 @@ // template class variant; // template -// void emplace(initializer_list il,Args&&... args); +// T& emplace(initializer_list il,Args&&... args); #include #include @@ -70,13 +70,19 @@ void test_emplace_sfinae() { void test_basic() { using V = std::variant; V v; - v.emplace({1, 2, 3}); + auto& ref1 = v.emplace({1, 2, 3}); + static_assert(std::is_same_v, ""); assert(std::get(v).size == 3); - v.emplace({1, 2, 3, 4}, 42); + assert(&ref1 == &std::get(v)); + auto& ref2 = v.emplace({1, 2, 3, 4}, 42); + static_assert(std::is_same_v, ""); assert(std::get(v).size == 4); assert(std::get(v).value == 42); - v.emplace({1}); + assert(&ref2 == &std::get(v)); + auto& ref3 = v.emplace({1}); + static_assert(std::is_same_v, ""); assert(std::get(v).size == 1); + assert(&ref3 == &std::get(v)); } int main() { diff --git a/www/cxx1z_status.html b/www/cxx1z_status.html index d4fd8ec62..dba9ef734 100644 --- a/www/cxx1z_status.html +++ b/www/cxx1z_status.html @@ -464,7 +464,7 @@ 2850std::function move constructor does unnecessary workKona 2853Possible inconsistency in specification of erase in [vector.modifiers]Kona 2855std::throw_with_nested("string_literal")KonaComplete - 2857{variant,optional,any}::emplace should return the constructed valueKona + 2857{variant,optional,any}::emplace should return the constructed valueKonaComplete 2861basic_string should require that charT match traits::char_typeKonaComplete 2866Incorrect derived classes constraintsKona 2868Missing specification of bad_any_cast::what()KonaComplete