diff --git a/include/boost/hana/basic_tuple.hpp b/include/boost/hana/basic_tuple.hpp index dbc762fb1..e0e8dcccc 100644 --- a/include/boost/hana/basic_tuple.hpp +++ b/include/boost/hana/basic_tuple.hpp @@ -15,6 +15,7 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include +#include #include #include #include @@ -72,7 +73,7 @@ BOOST_HANA_NAMESPACE_BEGIN ////////////////////////////////////////////////////////////////////////// //! @cond template - struct basic_tuple final + struct basic_tuple : detail::basic_tuple_impl, Xn...> { using Base = detail::basic_tuple_impl, Xn...>; @@ -176,28 +177,75 @@ BOOST_HANA_NAMESPACE_BEGIN ////////////////////////////////////////////////////////////////////////// template <> struct at_impl { - template - static constexpr decltype(auto) apply(Xs&& xs, N const&) { + template + static constexpr decltype(auto) apply(hana::basic_tuple& xs, N const&) { + constexpr std::size_t index = N::value; + using Nth = typename detail::type_at::type; + return detail::ebo_get>( + static_cast, Nth>&>(xs) + ); + } + + template + static constexpr decltype(auto) apply(hana::basic_tuple&& xs, N const&) { constexpr std::size_t index = N::value; - return detail::ebo_get>(static_cast(xs)); + using Nth = typename detail::type_at::type; + return detail::ebo_get>( + static_cast, Nth>&&>(xs) + ); + } + + template + static constexpr decltype(auto) apply(hana::basic_tuple const& xs, N const&) { + constexpr std::size_t index = N::value; + using Nth = typename detail::type_at::type; + return detail::ebo_get>( + static_cast, Nth> const&>(xs) + ); } }; template <> struct drop_front_impl { - template - static constexpr auto drop_front_helper(Xs&& xs, std::index_sequence) { + template + static constexpr auto + drop_front_helper(hana::basic_tuple&& xs, std::index_sequence) { return hana::make_basic_tuple( - detail::ebo_get>(static_cast(xs))... + detail::ebo_get>( + static_cast, typename detail::type_at::type + >&&>(xs) + )... + ); + } + template + static constexpr auto + drop_front_helper(hana::basic_tuple& xs, std::index_sequence) { + return hana::make_basic_tuple( + detail::ebo_get>( + static_cast, typename detail::type_at::type + >&>(xs) + )... + ); + } + template + static constexpr auto + drop_front_helper(hana::basic_tuple const& xs, std::index_sequence) { + return hana::make_basic_tuple( + detail::ebo_get>( + static_cast, typename detail::type_at::type + > const&>(xs) + )... ); } template static constexpr auto apply(Xs&& xs, N const&) { constexpr std::size_t len = detail::decay::type::size_; - return drop_front_helper(static_cast(xs), std::make_index_sequence< - N::value < len ? len - N::value : 0 - >{}); + using Indices = std::make_index_sequence; + return drop_front_helper(static_cast(xs), Indices{}); } }; @@ -212,17 +260,26 @@ BOOST_HANA_NAMESPACE_BEGIN // compile-time optimizations (to reduce the # of function instantiations) template constexpr decltype(auto) at_c(basic_tuple const& xs) { - return detail::ebo_get>(xs); + using Nth = typename detail::type_at::type; + return detail::ebo_get>( + static_cast, Nth> const&>(xs) + ); } template constexpr decltype(auto) at_c(basic_tuple& xs) { - return detail::ebo_get>(xs); + using Nth = typename detail::type_at::type; + return detail::ebo_get>( + static_cast, Nth>&>(xs) + ); } template constexpr decltype(auto) at_c(basic_tuple&& xs) { - return detail::ebo_get>(static_cast&&>(xs)); + using Nth = typename detail::type_at::type; + return detail::ebo_get>( + static_cast, Nth>&&>(xs) + ); } ////////////////////////////////////////////////////////////////////////// diff --git a/test/basic_tuple/drop_front.cpp b/test/basic_tuple/drop_front.cpp new file mode 100644 index 000000000..a0834fc18 --- /dev/null +++ b/test/basic_tuple/drop_front.cpp @@ -0,0 +1,18 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include +#include +#include +namespace hana = boost::hana; + + +template +struct x { }; + +int main() { + // Make sure drop_front works with nested tuples + hana::basic_tuple, hana::basic_tuple, x<2>>> tuple; + auto all = hana::drop_front(tuple, hana::size_c<0>); (void)all; +} diff --git a/test/basic_tuple/empty_storage.cpp b/test/basic_tuple/empty_storage.cpp new file mode 100644 index 000000000..10e770165 --- /dev/null +++ b/test/basic_tuple/empty_storage.cpp @@ -0,0 +1,27 @@ +// Copyright Louis Dionne 2013-2017 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#include + +#include +namespace hana = boost::hana; + + +struct empty1 { }; +struct empty2 { }; +struct empty3 { }; + + +// Make sure the storage of a basic_tuple is compressed. +static_assert(sizeof(hana::basic_tuple) == sizeof(int), ""); +static_assert(sizeof(hana::basic_tuple) == sizeof(int), ""); + +// Also make sure that a basic_tuple with only empty members is empty. This is +// important to ensure, for example, that a tuple of tuples of empty objects +// will get the EBO. We also test the nested case to be sure. +static_assert(std::is_empty>{}, ""); +static_assert(std::is_empty>>{}, ""); + + +int main() { } diff --git a/test/pair/empty_storage.cpp b/test/pair/empty_storage.cpp index cdea66cb9..5331dacb6 100644 --- a/test/pair/empty_storage.cpp +++ b/test/pair/empty_storage.cpp @@ -8,16 +8,20 @@ namespace hana = boost::hana; -// Make sure the storage of a pair is compressed -struct empty { }; -static_assert(sizeof(hana::pair) == sizeof(int), ""); -static_assert(sizeof(hana::pair) == sizeof(int), ""); - -// Also make sure that a pair with only empty members is empty too. This is -// important to ensure, for example, that a tuple of pairs of empty objects -// will get the EBO. struct empty1 { }; struct empty2 { }; +struct empty3 { }; + + +// Make sure the storage of a pair is compressed. +static_assert(sizeof(hana::pair) == sizeof(int), ""); +static_assert(sizeof(hana::pair) == sizeof(int), ""); + +// Also make sure that a pair with only empty members is empty. This is +// important to ensure, for example, that a tuple of pairs of empty +// objects will get the EBO. We also test the nested case. static_assert(std::is_empty>{}, ""); +static_assert(std::is_empty>>{}, ""); + int main() { }