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.

llvm-svn: 300403
This commit is contained in:
Eric Fiselier 2017-04-15 19:32:02 +00:00
parent ef9f586bb2
commit 2551475596
6 changed files with 102 additions and 47 deletions

View File

@ -53,16 +53,16 @@ namespace std {
// 20.7.2.4, modifiers
template <class T, class... Args>
void emplace(Args&&...);
T& emplace(Args&&...);
template <class T, class U, class... Args>
void emplace(initializer_list<U>, Args&&...);
T& emplace(initializer_list<U>, Args&&...);
template <size_t I, class... Args>
void emplace(Args&&...);
variant_alternative_t<I, variant>& emplace(Args&&...);
template <size_t I, class U, class... Args>
void emplace(initializer_list<U>, Args&&...);
variant_alternative_t<I, variant>& emplace(initializer_list<U>, Args&&...);
// 20.7.2.5, value status
constexpr bool valueless_by_exception() const noexcept;
@ -764,9 +764,10 @@ public:
protected:
template <size_t _Ip, class _Tp, class... _Args>
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 <class _Rhs>
@ -876,11 +877,12 @@ public:
template <size_t _Ip, class... _Args>
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<is_constructible_v<_Tp, _Args...>, 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<is_constructible_v<_Tp, initializer_list<_Up>&, _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<is_constructible_v<_Tp, _Args...>, 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<is_constructible_v<_Tp, initializer_list<_Up>&, _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

View File

@ -14,7 +14,8 @@
// template <class ...Types> class variant;
// template <size_t I, class ...Args> void emplace(Args&&... args);
// template <size_t I, class ...Args>
// variant_alternative_t<I, variant<Types...>>& emplace(Args&&... args);
#include <cassert>
#include <string>
@ -85,10 +86,14 @@ void test_basic() {
{
using V = std::variant<int>;
V v(42);
v.emplace<0>();
auto& ref1 = v.emplace<0>();
static_assert(std::is_same_v<int&, decltype(ref1)>, "");
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<int&, decltype(ref2)>, "");
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<long&, decltype(ref1)>, "");
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<const void*&, decltype(ref2)>, "");
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<std::string&, decltype(ref3)>, "");
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<long&, decltype(ref1)>, "");
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<std::string&, decltype(ref5)>, "");
assert(std::get<5>(v) == "aaa");
assert(&ref5 == &std::get<5>(v));
}
#endif
}

View File

@ -15,7 +15,7 @@
// template <class ...Types> class variant;
// template <size_t I, class U, class ...Args>
// void emplace(initializer_list<U> il,Args&&... args);
// variant_alternative_t<I, variant<Types...>>& emplace(initializer_list<U> il,Args&&... args);
#include <cassert>
#include <string>
@ -70,13 +70,19 @@ void test_emplace_sfinae() {
void test_basic() {
using V = std::variant<int, InitList, InitListArg, TestTypes::NoCtors>;
V v;
v.emplace<1>({1, 2, 3});
auto& ref1 = v.emplace<1>({1, 2, 3});
static_assert(std::is_same_v<InitList&, decltype(ref1)>, "");
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<InitListArg&, decltype(ref2)>, "");
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<InitList&, decltype(ref3)>, "");
assert(std::get<1>(v).size == 1);
assert(&ref3 == &std::get<1>(v));
}
int main() {

View File

@ -14,7 +14,7 @@
// template <class ...Types> class variant;
// template <class T, class ...Args> void emplace(Args&&... args);
// template <class T, class ...Args> T& emplace(Args&&... args);
#include <cassert>
#include <string>
@ -86,10 +86,14 @@ void test_basic() {
{
using V = std::variant<int>;
V v(42);
v.emplace<int>();
auto& ref1 = v.emplace<int>();
static_assert(std::is_same_v<int&, decltype(ref1)>, "");
assert(std::get<0>(v) == 0);
v.emplace<int>(42);
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 =
@ -97,13 +101,19 @@ void test_basic() {
const int x = 100;
V v(std::in_place_type<int>, -1);
// default emplace a value
v.emplace<long>();
auto& ref1 = v.emplace<long>();
static_assert(std::is_same_v<long&, decltype(ref1)>, "");
assert(std::get<1>(v) == 0);
v.emplace<const void *>(&x);
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
v.emplace<std::string>(3, 'a');
auto& ref3 = v.emplace<std::string>(3, '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)
{
@ -114,20 +124,30 @@ void test_basic() {
int z = 43;
V v(std::in_place_index<0>, -1);
// default emplace a value
v.emplace<long>();
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
v.emplace<const int &>(x);
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
v.emplace<int &&>(std::move(y));
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
v.emplace<int &&>(std::move(z));
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
v.emplace<std::string>(3, 'a');
auto& ref5 = v.emplace<std::string>(3, '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
}

View File

@ -15,7 +15,7 @@
// template <class ...Types> class variant;
// template <class T, class U, class ...Args>
// void emplace(initializer_list<U> il,Args&&... args);
// T& emplace(initializer_list<U> il,Args&&... args);
#include <cassert>
#include <string>
@ -70,13 +70,19 @@ void test_emplace_sfinae() {
void test_basic() {
using V = std::variant<int, InitList, InitListArg, TestTypes::NoCtors>;
V v;
v.emplace<InitList>({1, 2, 3});
auto& ref1 = v.emplace<InitList>({1, 2, 3});
static_assert(std::is_same_v<InitList&,decltype(ref1)>, "");
assert(std::get<InitList>(v).size == 3);
v.emplace<InitListArg>({1, 2, 3, 4}, 42);
assert(&ref1 == &std::get<InitList>(v));
auto& ref2 = v.emplace<InitListArg>({1, 2, 3, 4}, 42);
static_assert(std::is_same_v<InitListArg&,decltype(ref2)>, "");
assert(std::get<InitListArg>(v).size == 4);
assert(std::get<InitListArg>(v).value == 42);
v.emplace<InitList>({1});
assert(&ref2 == &std::get<InitListArg>(v));
auto& ref3 = v.emplace<InitList>({1});
static_assert(std::is_same_v<InitList&,decltype(ref3)>, "");
assert(std::get<InitList>(v).size == 1);
assert(&ref3 == &std::get<InitList>(v));
}
int main() {

View File

@ -464,7 +464,7 @@
<tr><td><a href="http://wg21.link/LWG2850">2850</a></td><td>std::function move constructor does unnecessary work</td><td>Kona</td><td></td></tr>
<tr><td><a href="http://wg21.link/LWG2853">2853</a></td><td>Possible inconsistency in specification of erase in [vector.modifiers]</td><td>Kona</td><td></td></tr>
<tr><td><a href="http://wg21.link/LWG2855">2855</a></td><td>std::throw_with_nested("string_literal")</td><td>Kona</td><td>Complete</td></tr>
<tr><td><a href="http://wg21.link/LWG2857">2857</a></td><td>{variant,optional,any}::emplace should return the constructed value</td><td>Kona</td><td></td></tr>
<tr><td><a href="http://wg21.link/LWG2857">2857</a></td><td>{variant,optional,any}::emplace should return the constructed value</td><td>Kona</td><td>Complete</td></tr>
<tr><td><a href="http://wg21.link/LWG2861">2861</a></td><td>basic_string should require that charT match traits::char_type</td><td>Kona</td><td>Complete</td></tr>
<tr><td><a href="http://wg21.link/LWG2866">2866</a></td><td>Incorrect derived classes constraints</td><td>Kona</td><td></td></tr>
<tr><td><a href="http://wg21.link/LWG2868">2868</a></td><td>Missing specification of bad_any_cast::what()</td><td>Kona</td><td>Complete</td></tr>