Home | History | Annotate | Download | only in tuple.apply
      1 //===----------------------------------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 // UNSUPPORTED: c++98, c++03, c++11, c++14
     11 
     12 // <tuple>
     13 
     14 // template <class T, class Tuple> constexpr T make_from_tuple(Tuple&&);
     15 
     16 #include <tuple>
     17 #include <array>
     18 #include <utility>
     19 #include <string>
     20 #include <cassert>
     21 
     22 #include "test_macros.h"
     23 #include "type_id.h"
     24 
     25 // std::array is explicitly allowed to be initialized with A a = { init-list };.
     26 // Disable the missing braces warning for this reason.
     27 #include "disable_missing_braces_warning.h"
     28 
     29 template <class Tuple>
     30 struct ConstexprConstructibleFromTuple {
     31   template <class ...Args>
     32   explicit constexpr ConstexprConstructibleFromTuple(Args&&... xargs)
     33       : args{std::forward<Args>(xargs)...} {}
     34   Tuple args;
     35 };
     36 
     37 template <class TupleLike>
     38 struct ConstructibleFromTuple;
     39 
     40 template <template <class ...> class Tuple, class ...Types>
     41 struct ConstructibleFromTuple<Tuple<Types...>> {
     42   template <class ...Args>
     43   explicit ConstructibleFromTuple(Args&&... xargs)
     44       : args(xargs...),
     45         arg_types(&makeArgumentID<Args&&...>())
     46   {}
     47   Tuple<std::decay_t<Types>...> args;
     48   TypeID const* arg_types;
     49 };
     50 
     51 template <class Tp, size_t N>
     52 struct ConstructibleFromTuple<std::array<Tp, N>> {
     53 template <class ...Args>
     54   explicit ConstructibleFromTuple(Args&&... xargs)
     55       : args{xargs...},
     56         arg_types(&makeArgumentID<Args&&...>())
     57   {}
     58   std::array<Tp, N> args;
     59   TypeID const* arg_types;
     60 };
     61 
     62 template <class Tuple>
     63 constexpr bool do_constexpr_test(Tuple&& tup) {
     64     using RawTuple = std::decay_t<Tuple>;
     65     using Tp = ConstexprConstructibleFromTuple<RawTuple>;
     66     return std::make_from_tuple<Tp>(std::forward<Tuple>(tup)).args == tup;
     67 }
     68 
     69 // Needed by do_forwarding_test() since it compares pairs of different types.
     70 template <class T1, class T2, class U1, class U2>
     71 inline bool operator==(const std::pair<T1, T2>& lhs, const std::pair<U1, U2>& rhs) {
     72     return lhs.first == rhs.first && lhs.second == rhs.second;
     73 }
     74 
     75 template <class ...ExpectTypes, class Tuple>
     76 bool do_forwarding_test(Tuple&& tup) {
     77     using RawTuple = std::decay_t<Tuple>;
     78     using Tp = ConstructibleFromTuple<RawTuple>;
     79     const Tp value = std::make_from_tuple<Tp>(std::forward<Tuple>(tup));
     80     return value.args == tup
     81         && value.arg_types == &makeArgumentID<ExpectTypes...>();
     82 }
     83 
     84 void test_constexpr_construction() {
     85     {
     86         constexpr std::tuple<> tup;
     87         static_assert(do_constexpr_test(tup), "");
     88     }
     89     {
     90         constexpr std::tuple<int> tup(42);
     91         static_assert(do_constexpr_test(tup), "");
     92     }
     93     {
     94         constexpr std::tuple<int, long, void*> tup(42, 101, nullptr);
     95         static_assert(do_constexpr_test(tup), "");
     96     }
     97     {
     98         constexpr std::pair<int, const char*> p(42, "hello world");
     99         static_assert(do_constexpr_test(p), "");
    100     }
    101     {
    102         using Tuple = std::array<int, 3>;
    103         using ValueTp = ConstexprConstructibleFromTuple<Tuple>;
    104         constexpr Tuple arr = {42, 101, -1};
    105         constexpr ValueTp value = std::make_from_tuple<ValueTp>(arr);
    106         static_assert(value.args[0] == arr[0] && value.args[1] == arr[1]
    107             && value.args[2] == arr[2], "");
    108     }
    109 }
    110 
    111 void test_perfect_forwarding() {
    112     {
    113         using Tup = std::tuple<>;
    114         Tup tup;
    115         Tup const& ctup = tup;
    116         assert(do_forwarding_test<>(tup));
    117         assert(do_forwarding_test<>(ctup));
    118     }
    119     {
    120         using Tup = std::tuple<int>;
    121         Tup tup(42);
    122         Tup const& ctup = tup;
    123         assert(do_forwarding_test<int&>(tup));
    124         assert(do_forwarding_test<int const&>(ctup));
    125         assert(do_forwarding_test<int&&>(std::move(tup)));
    126         assert(do_forwarding_test<int const&&>(std::move(ctup)));
    127     }
    128     {
    129         using Tup = std::tuple<int&, const char*, unsigned&&>;
    130         int x = 42;
    131         unsigned y = 101;
    132         Tup tup(x, "hello world", std::move(y));
    133         Tup const& ctup = tup;
    134         assert((do_forwarding_test<int&, const char*&, unsigned&>(tup)));
    135         assert((do_forwarding_test<int&, const char* const&, unsigned &>(ctup)));
    136         assert((do_forwarding_test<int&, const char*&&, unsigned&&>(std::move(tup))));
    137         assert((do_forwarding_test<int&, const char* const&&, unsigned &&>(std::move(ctup))));
    138     }
    139     // test with pair<T, U>
    140     {
    141         using Tup = std::pair<int&, const char*>;
    142         int x = 42;
    143         Tup tup(x, "hello world");
    144         Tup const& ctup = tup;
    145         assert((do_forwarding_test<int&, const char*&>(tup)));
    146         assert((do_forwarding_test<int&, const char* const&>(ctup)));
    147         assert((do_forwarding_test<int&, const char*&&>(std::move(tup))));
    148         assert((do_forwarding_test<int&, const char* const&&>(std::move(ctup))));
    149     }
    150     // test with array<T, I>
    151     {
    152         using Tup = std::array<int, 3>;
    153         Tup tup = {42, 101, -1};
    154         Tup const& ctup = tup;
    155         assert((do_forwarding_test<int&, int&, int&>(tup)));
    156         assert((do_forwarding_test<int const&, int const&, int const&>(ctup)));
    157         assert((do_forwarding_test<int&&, int&&, int&&>(std::move(tup))));
    158         assert((do_forwarding_test<int const&&, int const&&, int const&&>(std::move(ctup))));
    159     }
    160 }
    161 
    162 void test_noexcept() {
    163     struct NothrowMoveable {
    164       NothrowMoveable() = default;
    165       NothrowMoveable(NothrowMoveable const&) {}
    166       NothrowMoveable(NothrowMoveable&&) noexcept {}
    167     };
    168     struct TestType {
    169       TestType(int, NothrowMoveable) noexcept {}
    170       TestType(int, int, int) noexcept(false) {}
    171       TestType(long, long, long) noexcept {}
    172     };
    173     {
    174         using Tuple = std::tuple<int, NothrowMoveable>;
    175         Tuple tup; ((void)tup);
    176         Tuple const& ctup = tup; ((void)ctup);
    177         ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(ctup));
    178         LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(std::move(tup)));
    179     }
    180     {
    181         using Tuple = std::pair<int, NothrowMoveable>;
    182         Tuple tup; ((void)tup);
    183         Tuple const& ctup = tup; ((void)ctup);
    184         ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(ctup));
    185         LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(std::move(tup)));
    186     }
    187     {
    188         using Tuple = std::tuple<int, int, int>;
    189         Tuple tup; ((void)tup);
    190         ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
    191     }
    192     {
    193         using Tuple = std::tuple<long, long, long>;
    194         Tuple tup; ((void)tup);
    195         LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
    196     }
    197     {
    198         using Tuple = std::array<int, 3>;
    199         Tuple tup; ((void)tup);
    200         ASSERT_NOT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
    201     }
    202     {
    203         using Tuple = std::array<long, 3>;
    204         Tuple tup; ((void)tup);
    205         LIBCPP_ASSERT_NOEXCEPT(std::make_from_tuple<TestType>(tup));
    206     }
    207 }
    208 
    209 int main()
    210 {
    211     test_constexpr_construction();
    212     test_perfect_forwarding();
    213     test_noexcept();
    214 }
    215