diff --git a/include/__tuple b/include/__tuple index 57581e84..8c317597 100644 --- a/include/__tuple +++ b/include/__tuple @@ -86,6 +86,11 @@ template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 typename tuple_element<_Ip, tuple<_Tp...> >::type&& get(tuple<_Tp...>&&) _NOEXCEPT; + +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 +const typename tuple_element<_Ip, tuple<_Tp...> >::type&& +get(const tuple<_Tp...>&&) _NOEXCEPT; #endif // pair specializations @@ -109,6 +114,11 @@ template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 typename tuple_element<_Ip, pair<_T1, _T2> >::type&& get(pair<_T1, _T2>&&) _NOEXCEPT; + +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 +const typename tuple_element<_Ip, pair<_T1, _T2> >::type&& +get(const pair<_T1, _T2>&&) _NOEXCEPT; #endif // array specializations @@ -132,6 +142,11 @@ template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 _Tp&& get(array<_Tp, _Size>&&) _NOEXCEPT; + +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 +const _Tp&& +get(const array<_Tp, _Size>&&) _NOEXCEPT; #endif #if !defined(_LIBCPP_HAS_NO_VARIADICS) diff --git a/include/array b/include/array index 36096905..8866eaf6 100644 --- a/include/array +++ b/include/array @@ -95,6 +95,7 @@ template struct tuple_element>; template T& get(array&) noexcept; // constexpr in C++14 template const T& get(const array&) noexcept; // constexpr in C++14 template T&& get(array&&) noexcept; // constexpr in C++14 +template const T&& get(const array&&) noexcept; // constexpr in C++14 } // std @@ -324,6 +325,15 @@ get(array<_Tp, _Size>&& __a) _NOEXCEPT return _VSTD::move(__a.__elems_[_Ip]); } +template +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 +const _Tp&& +get(const array<_Tp, _Size>&& __a) _NOEXCEPT +{ + static_assert(_Ip < _Size, "Index out of bounds in std::get<> (const std::array &&)"); + return _VSTD::move(__a.__elems_[_Ip]); +} + #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES _LIBCPP_END_NAMESPACE_STD diff --git a/include/tuple b/include/tuple index 837be6fa..cb1e27d9 100644 --- a/include/tuple +++ b/include/tuple @@ -95,6 +95,9 @@ template template typename tuple_element>::type&& get(tuple&&) noexcept; // constexpr in C++14 +template + const typename tuple_element>::type&& + get(const tuple&&) noexcept; // constexpr in C++14 template constexpr T1& get(tuple&) noexcept; // C++14 @@ -102,6 +105,8 @@ template constexpr const T1& get(const tuple&) noexcept; // C++14 template constexpr T1&& get(tuple&&) noexcept; // C++14 +template + constexpr const T1&& get(const tuple&&) noexcept; // C++14 // 20.4.1.6, relational operators: template bool operator==(const tuple&, const tuple&); // constexpr in C++14 @@ -507,6 +512,8 @@ class _LIBCPP_TYPE_VIS_ONLY tuple const typename tuple_element<_Jp, tuple<_Up...> >::type& get(const tuple<_Up...>&) _NOEXCEPT; template friend _LIBCPP_CONSTEXPR_AFTER_CXX11 typename tuple_element<_Jp, tuple<_Up...> >::type&& get(tuple<_Up...>&&) _NOEXCEPT; + template friend _LIBCPP_CONSTEXPR_AFTER_CXX11 + const typename tuple_element<_Jp, tuple<_Up...> >::type&& get(const tuple<_Up...>&&) _NOEXCEPT; public: template && __t) _NOEXCEPT static_cast<__tuple_leaf<_Ip, type>&&>(__t.base_).get()); } +template +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 +const typename tuple_element<_Ip, tuple<_Tp...> >::type&& +get(const tuple<_Tp...>&& __t) _NOEXCEPT +{ + typedef typename tuple_element<_Ip, tuple<_Tp...> >::type type; + return static_cast( + static_cast&&>(__t.base_).get()); +} + #if _LIBCPP_STD_VER > 11 // get by type template @@ -822,6 +839,13 @@ constexpr _T1&& get(tuple<_Args...>&& __tup) noexcept return _VSTD::get<__find_exactly_one_t<_T1, _Args...>::value>(_VSTD::move(__tup)); } +template +inline _LIBCPP_INLINE_VISIBILITY +constexpr _T1 const&& get(tuple<_Args...> const&& __tup) noexcept +{ + return _VSTD::get<__find_exactly_one_t<_T1, _Args...>::value>(_VSTD::move(__tup)); +} + #endif // tie diff --git a/include/utility b/include/utility index 8b376615..4d0191c4 100644 --- a/include/utility +++ b/include/utility @@ -120,15 +120,34 @@ template typename tuple_element >::type&& get(pair&&) noexcept; // constexpr in C++14 +template + const typename tuple_element >::type&& + get(const pair&&) noexcept; // constexpr in C++14 + template constexpr T1& get(pair&) noexcept; // C++14 -template +template constexpr const T1& get(const pair&) noexcept; // C++14 -template +template constexpr T1&& get(pair&&) noexcept; // C++14 +template + constexpr const T1&& get(const pair&&) noexcept; // C++14 + +template + constexpr T1& get(pair&) noexcept; // C++14 + +template + constexpr const T1& get(const pair&) noexcept; // C++14 + +template + constexpr T1&& get(pair&&) noexcept; // C++14 + +template + constexpr const T1&& get(const pair&&) noexcept; // C++14 + // C++14 template @@ -560,6 +579,12 @@ struct __get_pair<0> _T1&& get(pair<_T1, _T2>&& __p) _NOEXCEPT {return _VSTD::forward<_T1>(__p.first);} + template + static + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + const _T1&& + get(const pair<_T1, _T2>&& __p) _NOEXCEPT {return _VSTD::forward(__p.first);} + #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES }; @@ -586,6 +611,12 @@ struct __get_pair<1> _T2&& get(pair<_T1, _T2>&& __p) _NOEXCEPT {return _VSTD::forward<_T2>(__p.second);} + template + static + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + const _T2&& + get(const pair<_T1, _T2>&& __p) _NOEXCEPT {return _VSTD::forward(__p.second);} + #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES }; @@ -615,6 +646,14 @@ get(pair<_T1, _T2>&& __p) _NOEXCEPT return __get_pair<_Ip>::get(_VSTD::move(__p)); } +template +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 +const typename tuple_element<_Ip, pair<_T1, _T2> >::type&& +get(const pair<_T1, _T2>&& __p) _NOEXCEPT +{ + return __get_pair<_Ip>::get(_VSTD::move(__p)); +} + #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES #if _LIBCPP_STD_VER > 11 @@ -639,6 +678,13 @@ constexpr _T1 && get(pair<_T1, _T2>&& __p) _NOEXCEPT return __get_pair<0>::get(_VSTD::move(__p)); } +template +inline _LIBCPP_INLINE_VISIBILITY +constexpr _T1 const && get(pair<_T1, _T2> const&& __p) _NOEXCEPT +{ + return __get_pair<0>::get(_VSTD::move(__p)); +} + template inline _LIBCPP_INLINE_VISIBILITY constexpr _T1 & get(pair<_T2, _T1>& __p) _NOEXCEPT @@ -660,6 +706,13 @@ constexpr _T1 && get(pair<_T2, _T1>&& __p) _NOEXCEPT return __get_pair<1>::get(_VSTD::move(__p)); } +template +inline _LIBCPP_INLINE_VISIBILITY +constexpr _T1 const && get(pair<_T2, _T1> const&& __p) _NOEXCEPT +{ + return __get_pair<1>::get(_VSTD::move(__p)); +} + #endif #if _LIBCPP_STD_VER > 11 diff --git a/test/std/containers/sequences/array/array.tuple/get_const_rv.pass.cpp b/test/std/containers/sequences/array/array.tuple/get_const_rv.pass.cpp new file mode 100644 index 00000000..a22c91a4 --- /dev/null +++ b/test/std/containers/sequences/array/array.tuple/get_const_rv.pass.cpp @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// template const T&& get(const array&& a); + +// UNSUPPORTED: c++98, c++03 + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +// std::array is explicitly allowed to be initialized with A a = { init-list };. +// Disable the missing braces warning for this reason. +#include "disable_missing_braces_warning.h" + +int main() +{ + + { + typedef std::unique_ptr T; + typedef std::array C; + const C c = {std::unique_ptr(new double(3.5))}; + static_assert(std::is_same(std::move(c)))>::value, ""); + static_assert(noexcept(std::get<0>(std::move(c))), ""); + const T&& t = std::get<0>(std::move(c)); + assert(*t == 3.5); + } + +#if TEST_STD_VER > 11 + { + typedef double T; + typedef std::array C; + constexpr const C c = {1, 2, 3.5}; + static_assert(std::get<0>(std::move(c)) == 1, ""); + static_assert(std::get<1>(std::move(c)) == 2, ""); + static_assert(std::get<2>(std::move(c)) == 3.5, ""); + } +#endif +} diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const_rv.fail.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const_rv.fail.cpp new file mode 100644 index 00000000..58df2df7 --- /dev/null +++ b/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const_rv.fail.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// template class tuple; + +// template +// const typename tuple_element >::type&& +// get(const tuple&& t); + +// UNSUPPORTED: c++98, c++03 + +#include + +template void cref(T const&) {}; +template void cref(T const&&) = delete; + +std::tuple const tup4() { return std::make_tuple(4); } + +int main() +{ + // LWG2485: tuple should not open a hole in the type system, get() should + // imitate [expr.ref]'s rules for accessing data members + { + cref(std::get<0>(tup4())); // expected-error {{call to deleted function 'cref'}} + } +} diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const_rv.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const_rv.pass.cpp new file mode 100644 index 00000000..720a9064 --- /dev/null +++ b/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const_rv.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// template class tuple; + +// template +// const typename tuple_element >::type&& +// get(const tuple&& t); + +// UNSUPPORTED: c++98, c++03 + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +int main() +{ + { + typedef std::tuple T; + const T t(3); + static_assert(std::is_same(std::move(t)))>::value, ""); + static_assert(noexcept(std::get<0>(std::move(t))), ""); + const int&& i = std::get<0>(std::move(t)); + assert(i == 3); + } + + { + typedef std::tuple T; + const T t("high", 5); + static_assert(std::is_same(std::move(t)))>::value, ""); + static_assert(noexcept(std::get<0>(std::move(t))), ""); + static_assert(std::is_same(std::move(t)))>::value, ""); + static_assert(noexcept(std::get<1>(std::move(t))), ""); + const std::string&& s = std::get<0>(std::move(t)); + const int&& i = std::get<1>(std::move(t)); + assert(s == "high"); + assert(i == 5); + } + + { + int x = 42; + int const y = 43; + std::tuple const p(x, y); + static_assert(std::is_same(std::move(p)))>::value, ""); + static_assert(noexcept(std::get<0>(std::move(p))), ""); + static_assert(std::is_same(std::move(p)))>::value, ""); + static_assert(noexcept(std::get<1>(std::move(p))), ""); + } + + { + int x = 42; + int const y = 43; + std::tuple const p(std::move(x), std::move(y)); + static_assert(std::is_same(std::move(p)))>::value, ""); + static_assert(noexcept(std::get<0>(std::move(p))), ""); + static_assert(std::is_same(std::move(p)))>::value, ""); + static_assert(noexcept(std::get<1>(std::move(p))), ""); + } + +#if TEST_STD_VER > 11 + { + typedef std::tuple T; + constexpr const T t(2.718, 5); + static_assert(std::get<0>(std::move(t)) == 2.718, ""); + static_assert(std::get<1>(std::move(t)) == 5, ""); + } +#endif +} diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.pass.cpp index aa020dab..7bbd0016 100644 --- a/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.pass.cpp +++ b/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.pass.cpp @@ -10,30 +10,31 @@ // UNSUPPORTED: c++98, c++03, c++11 #include +#include #include #include +#include #include int main() { -#if _LIBCPP_STD_VER > 11 typedef std::complex cf; { auto t1 = std::tuple { 42, "Hi", { 1,2 }}; - assert ( std::get(t1) == 42 ); // find at the beginning + assert ( std::get(t1) == 42 ); // find at the beginning assert ( std::get(t1) == "Hi" ); // find in the middle assert ( std::get(t1).real() == 1 ); // find at the end assert ( std::get(t1).imag() == 2 ); } - + { auto t2 = std::tuple { 42, "Hi", 23, { 1,2 }}; // get would fail! assert ( std::get(t2) == "Hi" ); assert (( std::get(t2) == cf{ 1,2 } )); } - + { constexpr std::tuple p5 { 1, 2, 3.4, 5.6 }; static_assert ( std::get(p5) == 1, "" ); @@ -53,8 +54,40 @@ int main() std::tuple t(upint(new int(4))); upint p = std::get(std::move(t)); // get rvalue assert(*p == 4); - assert(std::get<0>(t) == nullptr); // has been moved from + assert(std::get(t) == nullptr); // has been moved from } -#endif + { + typedef std::unique_ptr upint; + const std::tuple t(upint(new int(4))); + const upint&& p = std::get(std::move(t)); // get const rvalue + assert(*p == 4); + assert(std::get(t) != nullptr); + } + + { + int x = 42; + int tuple y = 43; + std::tuple const t(x, y); + static_assert(std::is_same(std::move(t)))>::value, ""); + static_assert(noexcept(std::get(std::move(t))), ""); + static_assert(std::is_same(std::move(t)))>::value, ""); + static_assert(noexcept(std::get(std::move(t))), ""); + } + + { + int x = 42; + int tuple y = 43; + std::tuple const t(std::move(x), std::move(y)); + static_assert(std::is_same(std::move(t)))>::value, ""); + static_assert(noexcept(std::get(std::move(t))), ""); + static_assert(std::is_same(std::move(t)))>::value, ""); + static_assert(noexcept(std::get(std::move(t))), ""); + } + + { + constexpr const std::tuple t { 1, 2, 3.4, 5.6 }; + static_assert(std::get(std::move(t)) == 1, ""); + static_assert(std::get(std::move(t)) == 2, ""); + } } diff --git a/test/std/utilities/utility/pairs/pair.astuple/get_const_rv.pass.cpp b/test/std/utilities/utility/pairs/pair.astuple/get_const_rv.pass.cpp new file mode 100644 index 00000000..edd2f3d0 --- /dev/null +++ b/test/std/utilities/utility/pairs/pair.astuple/get_const_rv.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// template struct pair + +// template +// const typename tuple_element >::type&& +// get(const pair&&); + +// UNSUPPORTED: c++98, c++03 + +#include +#include +#include +#include + +#include "test_macros.h" + +int main() +{ + { + typedef std::pair, short> P; + const P p(std::unique_ptr(new int(3)), 4); + static_assert(std::is_same&&, decltype(std::get<0>(std::move(p)))>::value, ""); + static_assert(noexcept(std::get<0>(std::move(p))), ""); + const std::unique_ptr&& ptr = std::get<0>(std::move(p)); + assert(*ptr == 3); + } + + { + int x = 42; + int const y = 43; + std::pair const p(x, y); + static_assert(std::is_same(std::move(p)))>::value, ""); + static_assert(noexcept(std::get<0>(std::move(p))), ""); + static_assert(std::is_same(std::move(p)))>::value, ""); + static_assert(noexcept(std::get<1>(std::move(p))), ""); + } + + { + int x = 42; + int const y = 43; + std::pair const p(std::move(x), std::move(y)); + static_assert(std::is_same(std::move(p)))>::value, ""); + static_assert(noexcept(std::get<0>(std::move(p))), ""); + static_assert(std::is_same(std::move(p)))>::value, ""); + static_assert(noexcept(std::get<1>(std::move(p))), ""); + } + +#if TEST_STD_VER > 11 + { + typedef std::pair P; + constexpr const P p1(3, 4); + static_assert(std::get<0>(std::move(p1)) == 3, ""); + static_assert(std::get<1>(std::move(p1)) == 4, ""); + } +#endif +} diff --git a/test/std/utilities/utility/pairs/pair.astuple/pairs.by.type.pass.cpp b/test/std/utilities/utility/pairs/pair.astuple/pairs.by.type.pass.cpp index 176d5833..efcc2ced 100644 --- a/test/std/utilities/utility/pairs/pair.astuple/pairs.by.type.pass.cpp +++ b/test/std/utilities/utility/pairs/pair.astuple/pairs.by.type.pass.cpp @@ -7,15 +7,17 @@ // //===----------------------------------------------------------------------===// +// UNSUPPORTED: c++98, c++03, c++11 + #include #include +#include #include #include int main() { -#if _LIBCPP_STD_VER > 11 typedef std::complex cf; { auto t1 = std::make_pair ( 42, { 1,2 } ); @@ -23,7 +25,7 @@ int main() assert ( std::get(t1).real() == 1 ); assert ( std::get(t1).imag() == 2 ); } - + { const std::pair p1 { 1, 2 }; const int &i1 = std::get(p1); @@ -35,10 +37,48 @@ int main() { typedef std::unique_ptr upint; std::pair t(upint(new int(4)), 42); - upint p = std::get<0>(std::move(t)); // get rvalue + upint p = std::get(std::move(t)); // get rvalue assert(*p == 4); - assert(std::get<0>(t) == nullptr); // has been moved from + assert(std::get(t) == nullptr); // has been moved from } -#endif + { + typedef std::unique_ptr upint; + const std::pair t(upint(new int(4)), 42); + static_assert(std::is_same(std::move(t)))>::value, ""); + static_assert(noexcept(std::get(std::move(t))), ""); + static_assert(std::is_same(std::move(t)))>::value, ""); + static_assert(noexcept(std::get(std::move(t))), ""); + auto&& p = std::get(std::move(t)); // get const rvalue + auto&& i = std::get(std::move(t)); // get const rvalue + assert(*p == 4); + assert(i == 42); + assert(std::get(t) != nullptr); + } + + { + int x = 42; + int const y = 43; + std::pair const p(x, y); + static_assert(std::is_same(std::move(p)))>::value, ""); + static_assert(noexcept(std::get(std::move(p))), ""); + static_assert(std::is_same(std::move(p)))>::value, ""); + static_assert(noexcept(std::get(std::move(p))), ""); + } + + { + int x = 42; + int const y = 43; + std::pair const p(std::move(x), std::move(y)); + static_assert(std::is_same(std::move(p)))>::value, ""); + static_assert(noexcept(std::get(std::move(p))), ""); + static_assert(std::is_same(std::move(p)))>::value, ""); + static_assert(noexcept(std::get(std::move(p))), ""); + } + + { + constexpr const std::pair p { 1, 2 }; + static_assert(std::get(std::move(p)) == 1, ""); + static_assert(std::get(std::move(p)) == 2, ""); + } } diff --git a/www/cxx1z_status.html b/www/cxx1z_status.html index 833f7b29..693bc3a9 100644 --- a/www/cxx1z_status.html +++ b/www/cxx1z_status.html @@ -179,7 +179,7 @@ 2477Inconsistency of wordings in std::vector::erase() and std::deque::erase()KonaComplete 2483throw_with_nested() should use is_finalKonaComplete 2484rethrow_if_nested() is doubly unimplementableKonaComplete - 2485get() should be overloaded for const tuple&&Kona + 2485get() should be overloaded for const tuple&&KonaCompleted 2486mem_fn() should be required to use perfect forwardingKonaComplete 2487bind() should be const-overloaded, not cv-overloadedKonaComplete 2489mem_fn() should be noexceptKonaComplete