xref: /llvm-project/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/test_lazy_sfinae.pass.cpp (revision 31cbe0f240f660f15602c96b787c58a26f17e179)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // <tuple>
10 
11 // template <class... Types> class tuple;
12 
13 // UNSUPPORTED: c++03
14 
15 #include <tuple>
16 #include <utility>
17 #include <cassert>
18 
19 #include "test_macros.h"
20 
21 template <class ConstructFrom>
22 struct ConstructibleFromT {
23   ConstructibleFromT() = default;
24   ConstructibleFromT(ConstructFrom v) : value(v) {}
25   ConstructFrom value;
26 };
27 
28 template <class AssertOn>
29 struct CtorAssertsT {
30   bool defaulted;
31   CtorAssertsT() : defaulted(true) {}
32   template <class T>
33   constexpr CtorAssertsT(T) : defaulted(false) {
34       static_assert(!std::is_same<T, AssertOn>::value, "");
35   }
36 };
37 
38 template <class AllowT, class AssertT>
39 struct AllowAssertT {
40   AllowAssertT() = default;
41   AllowAssertT(AllowT) {}
42   template <class U>
43   constexpr AllowAssertT(U) {
44       static_assert(!std::is_same<U, AssertT>::value, "");
45   }
46 };
47 
48 // Construct a tuple<T1, T2> from pair<int, int> where T1 and T2
49 // are not constructible from ints but T1 is constructible from std::pair.
50 // This considers the following constructors:
51 // (1) tuple(TupleLike) -> checks is_constructible<Tn, int>
52 // (2) tuple(UTypes...) -> checks is_constructible<T1, pair<int, int>>
53 //                            and is_default_constructible<T2>
54 // The point of this test is to ensure that the consideration of (1)
55 // short circuits before evaluating is_constructible<T2, int>, which
56 // will cause a static assertion.
57 void test_tuple_like_lazy_sfinae() {
58 #if defined(_LIBCPP_VERSION)
59     // This test requires libc++'s reduced arity initialization.
60     using T1 = ConstructibleFromT<std::pair<int, int>>;
61     using T2 = CtorAssertsT<int>;
62     std::pair<int, int> p(42, 100);
63     std::tuple<T1, T2> t(p);
64     assert(std::get<0>(t).value == p);
65     assert(std::get<1>(t).defaulted);
66 #endif
67 }
68 
69 
70 struct NonConstCopyable {
71   NonConstCopyable() = default;
72   explicit NonConstCopyable(int v) : value(v) {}
73   NonConstCopyable(NonConstCopyable&) = default;
74   NonConstCopyable(NonConstCopyable const&) = delete;
75   int value;
76 };
77 
78 template <class T>
79 struct BlowsUpOnConstCopy {
80   BlowsUpOnConstCopy() = default;
81   constexpr BlowsUpOnConstCopy(BlowsUpOnConstCopy const&) {
82       static_assert(!std::is_same<T, T>::value, "");
83   }
84   BlowsUpOnConstCopy(BlowsUpOnConstCopy&) = default;
85 };
86 
87 // Test the following constructors:
88 // (1) tuple(Types const&...)
89 // (2) tuple(UTypes&&...)
90 // Test that (1) short circuits before evaluating the copy constructor of the
91 // second argument. Constructor (2) should be selected.
92 void test_const_Types_lazy_sfinae()
93 {
94     NonConstCopyable v(42);
95     BlowsUpOnConstCopy<int> b;
96     std::tuple<NonConstCopyable, BlowsUpOnConstCopy<int>> t(v, b);
97     assert(std::get<0>(t).value == 42);
98 }
99 
100 int main(int, char**) {
101     test_tuple_like_lazy_sfinae();
102     test_const_Types_lazy_sfinae();
103 
104   return 0;
105 }
106