diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2015-01-17 00:21:41 +0000 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2015-01-17 00:21:41 +0000 |
commit | 3ecec1eff783311415180f8d53cbbf782698960f (patch) | |
tree | 77b157ad944f44ae17066eee6e3029272fa6a44b | |
parent | 3c16c4238bc17a160c9fc9b05fb8a91b8fcda5da (diff) | |
download | gcc-3ecec1eff783311415180f8d53cbbf782698960f.zip gcc-3ecec1eff783311415180f8d53cbbf782698960f.tar.gz gcc-3ecec1eff783311415180f8d53cbbf782698960f.tar.bz2 |
re PR libstdc++/56785 (std::tuple of two elements does not apply empty base class optimization when one of its elements is a std::tuple with two elements)
PR libstdc++/56785
* include/std/tuple (_Tuple_impl): Remove zero-element specialization
and define one-element specialization.
* testsuite/20_util/tuple/56785.cc: New.
From-SVN: r219785
-rw-r--r-- | libstdc++-v3/ChangeLog | 7 | ||||
-rw-r--r-- | libstdc++-v3/include/std/tuple | 148 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/tuple/56785.cc | 32 |
3 files changed, 163 insertions, 24 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index b0db0dc..ae4f3cc 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,12 @@ 2015-01-17 Jonathan Wakely <jwakely@redhat.com> + PR libstdc++/56785 + * include/std/tuple (_Tuple_impl): Remove zero-element specialization + and define one-element specialization. + * testsuite/20_util/tuple/56785.cc: New. + +2015-01-17 Jonathan Wakely <jwakely@redhat.com> + * testsuite/22_locale/codecvt/codecvt_utf8/requirements/1.cc: Remove unused header. * testsuite/22_locale/codecvt/codecvt_utf16/requirements/1.cc: diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index b710049..e500a76 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -158,30 +158,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<std::size_t _Idx, typename... _Elements> struct _Tuple_impl; - /** - * Zero-element tuple implementation. This is the basis case for the - * inheritance recursion. - */ - template<std::size_t _Idx> - struct _Tuple_impl<_Idx> - { - template<std::size_t, typename...> friend class _Tuple_impl; - - _Tuple_impl() = default; - - template<typename _Alloc> - _Tuple_impl(allocator_arg_t, const _Alloc&) { } - - template<typename _Alloc> - _Tuple_impl(allocator_arg_t, const _Alloc&, const _Tuple_impl&) { } - - template<typename _Alloc> - _Tuple_impl(allocator_arg_t, const _Alloc&, _Tuple_impl&&) { } - - protected: - void _M_swap(_Tuple_impl&) noexcept { /* no-op */ } - }; - template<typename _Tp> struct __is_empty_non_tuple : is_empty<_Tp> { }; @@ -358,6 +334,130 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; + // Basis case of inheritance recursion. + template<std::size_t _Idx, typename _Head> + struct _Tuple_impl<_Idx, _Head> + : private _Head_base<_Idx, _Head, __empty_not_final<_Head>::value> + { + template<std::size_t, typename...> friend class _Tuple_impl; + + typedef _Head_base<_Idx, _Head, __empty_not_final<_Head>::value> _Base; + + static constexpr _Head& + _M_head(_Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } + + static constexpr const _Head& + _M_head(const _Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } + + constexpr _Tuple_impl() + : _Base() { } + + explicit + constexpr _Tuple_impl(const _Head& __head) + : _Base(__head) { } + + template<typename _UHead> + explicit + constexpr _Tuple_impl(_UHead&& __head) + : _Base(std::forward<_UHead>(__head)) { } + + constexpr _Tuple_impl(const _Tuple_impl&) = default; + + constexpr + _Tuple_impl(_Tuple_impl&& __in) + noexcept(is_nothrow_move_constructible<_Head>::value) + : _Base(std::forward<_Head>(_M_head(__in))) { } + + template<typename _UHead> + constexpr _Tuple_impl(const _Tuple_impl<_Idx, _UHead>& __in) + : _Base(_Tuple_impl<_Idx, _UHead>::_M_head(__in)) { } + + template<typename _UHead> + constexpr _Tuple_impl(_Tuple_impl<_Idx, _UHead>&& __in) + : _Base(std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) + { } + + template<typename _Alloc> + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a) + : _Base(__tag, __use_alloc<_Head>(__a)) { } + + template<typename _Alloc> + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Head& __head) + : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), __head) { } + + template<typename _Alloc, typename _UHead> + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _UHead&& __head) + : _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), + std::forward<_UHead>(__head)) { } + + template<typename _Alloc> + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Tuple_impl& __in) + : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), _M_head(__in)) { } + + template<typename _Alloc> + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl&& __in) + : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), + std::forward<_Head>(_M_head(__in))) { } + + template<typename _Alloc, typename _UHead> + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Tuple_impl<_Idx, _UHead>& __in) + : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), + _Tuple_impl<_Idx, _UHead>::_M_head(__in)) { } + + template<typename _Alloc, typename _UHead> + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl<_Idx, _UHead>&& __in) + : _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), + std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) + { } + + _Tuple_impl& + operator=(const _Tuple_impl& __in) + { + _M_head(*this) = _M_head(__in); + return *this; + } + + _Tuple_impl& + operator=(_Tuple_impl&& __in) + noexcept(is_nothrow_move_assignable<_Head>::value) + { + _M_head(*this) = std::forward<_Head>(_M_head(__in)); + return *this; + } + + template<typename _UHead> + _Tuple_impl& + operator=(const _Tuple_impl<_Idx, _UHead>& __in) + { + _M_head(*this) = _Tuple_impl<_Idx, _UHead>::_M_head(__in); + return *this; + } + + template<typename _UHead> + _Tuple_impl& + operator=(_Tuple_impl<_Idx, _UHead>&& __in) + { + _M_head(*this) + = std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)); + return *this; + } + + protected: + void + _M_swap(_Tuple_impl& __in) + noexcept(noexcept(swap(std::declval<_Head&>(), std::declval<_Head&>()))) + { + using std::swap; + swap(_M_head(*this), _M_head(__in)); + } + }; + /// Primary class template, tuple template<typename... _Elements> class tuple : public _Tuple_impl<0, _Elements...> diff --git a/libstdc++-v3/testsuite/20_util/tuple/56785.cc b/libstdc++-v3/testsuite/20_util/tuple/56785.cc new file mode 100644 index 0000000..504ab0a --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/56785.cc @@ -0,0 +1,32 @@ +// Copyright (C) 2015 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +#include <tuple> + +class Empty { }; + +using std::tuple; +using char_pair = tuple<char, char>; + +static_assert( sizeof(tuple<Empty, char_pair>) == sizeof(char_pair), + "Nested tuple tuple<Empty, tuple<T,T>> is too big"); + +static_assert( sizeof(tuple<char_pair, char_pair>) == (2 * sizeof(char_pair)), + "Nested tuple<tuple<T,T, tuple<T,T>> is too big" ); |