Index: include/__tuple =================================================================== --- include/__tuple +++ include/__tuple @@ -86,6 +86,11 @@ _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 @@ _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 @@ _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) Index: include/array =================================================================== --- include/array +++ include/array @@ -95,6 +95,7 @@ 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 @@ 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 Index: include/tuple =================================================================== --- include/tuple +++ include/tuple @@ -95,6 +95,9 @@ 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 @@ 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 @@ 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.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 @@ 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 Index: include/utility =================================================================== --- include/utility +++ include/utility @@ -120,15 +120,34 @@ 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 @@ _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 @@ _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 @@ 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 @@ -641,6 +680,13 @@ 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 { return __get_pair<1>::get(__p); @@ -660,6 +706,13 @@ 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 Index: test/std/containers/sequences/array/array.tuple/get_const_rv.pass.cpp =================================================================== --- /dev/null +++ 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 +} Index: test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const_rv.fail.cpp =================================================================== --- /dev/null +++ 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'}} + } +} Index: test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const_rv.pass.cpp =================================================================== --- /dev/null +++ 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 +} Index: test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.pass.cpp =================================================================== --- test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.pass.cpp +++ 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 @@ 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 + } + + { + 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); } -#endif + { + 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, ""); + } } Index: test/std/utilities/utility/pairs/pair.astuple/get_const_rv.pass.cpp =================================================================== --- /dev/null +++ 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 +} Index: test/std/utilities/utility/pairs/pair.astuple/pairs.by.type.pass.cpp =================================================================== --- test/std/utilities/utility/pairs/pair.astuple/pairs.by.type.pass.cpp +++ 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 @@ 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 @@ { 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(t) == nullptr); // has been moved from + } + + { + 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(std::get<0>(t) == nullptr); // has been moved from + assert(i == 42); + assert(std::get(t) != nullptr); } -#endif + { + 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, ""); + } }