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 // UNSUPPORTED: c++03, c++11, c++14, c++17
10
11 // <memory>
12
13 // template <class T, class ...Args>
14 // constexpr T* construct_at(T* location, Args&& ...args);
15
16 #include <memory>
17 #include <cassert>
18 #include <utility>
19
20 #include "test_iterators.h"
21
22 struct Foo {
FooFoo23 constexpr Foo() { }
FooFoo24 constexpr Foo(int a, char b, double c) : a_(a), b_(b), c_(c) { }
FooFoo25 constexpr Foo(int a, char b, double c, int* count) : Foo(a, b, c) { *count += 1; }
operator ==Foo26 constexpr bool operator==(Foo const& other) const {
27 return a_ == other.a_ && b_ == other.b_ && c_ == other.c_;
28 }
29
30 private:
31 int a_;
32 char b_;
33 double c_;
34 };
35
36 struct Counted {
37 int& count_;
CountedCounted38 constexpr Counted(int& count) : count_(count) { ++count; }
CountedCounted39 constexpr Counted(Counted const& that) : count_(that.count_) { ++count_; }
~CountedCounted40 constexpr ~Counted() { --count_; }
41 };
42
test()43 constexpr bool test()
44 {
45 {
46 int i = 99;
47 int* res = std::construct_at(&i);
48 assert(res == &i);
49 assert(*res == 0);
50 }
51
52 {
53 int i = 0;
54 int* res = std::construct_at(&i, 42);
55 assert(res == &i);
56 assert(*res == 42);
57 }
58
59 {
60 Foo foo = {};
61 int count = 0;
62 Foo* res = std::construct_at(&foo, 42, 'x', 123.89, &count);
63 assert(res == &foo);
64 assert(*res == Foo(42, 'x', 123.89));
65 assert(count == 1);
66 }
67
68 {
69 std::allocator<Counted> a;
70 Counted* p = a.allocate(2);
71 int count = 0;
72 std::construct_at(p, count);
73 assert(count == 1);
74 std::construct_at(p+1, count);
75 assert(count == 2);
76 (p+1)->~Counted();
77 assert(count == 1);
78 p->~Counted();
79 assert(count == 0);
80 a.deallocate(p, 2);
81 }
82
83 {
84 std::allocator<Counted const> a;
85 Counted const* p = a.allocate(2);
86 int count = 0;
87 std::construct_at(p, count);
88 assert(count == 1);
89 std::construct_at(p+1, count);
90 assert(count == 2);
91 (p+1)->~Counted();
92 assert(count == 1);
93 p->~Counted();
94 assert(count == 0);
95 a.deallocate(p, 2);
96 }
97
98 return true;
99 }
100
101 template <class ...Args, class = decltype(std::construct_at(std::declval<Args>()...))>
can_construct_at(Args &&...)102 constexpr bool can_construct_at(Args&&...) { return true; }
103
104 template <class ...Args>
can_construct_at(...)105 constexpr bool can_construct_at(...) { return false; }
106
107 // Check that SFINAE works.
108 static_assert( can_construct_at((int*)nullptr, 42));
109 static_assert( can_construct_at((Foo*)nullptr, 1, '2', 3.0));
110 static_assert(!can_construct_at((Foo*)nullptr, 1, '2'));
111 static_assert(!can_construct_at((Foo*)nullptr, 1, '2', 3.0, 4));
112 static_assert(!can_construct_at(nullptr, 1, '2', 3.0));
113 static_assert(!can_construct_at((int*)nullptr, 1, '2', 3.0));
114 static_assert(!can_construct_at(contiguous_iterator<Foo*>(), 1, '2', 3.0));
115 // Can't construct function pointers.
116 static_assert(!can_construct_at((int(*)())nullptr));
117 static_assert(!can_construct_at((int(*)())nullptr, nullptr));
118
main(int,char **)119 int main(int, char**)
120 {
121 test();
122 static_assert(test());
123 return 0;
124 }
125