251 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// Test all the ways of initializing a std::array.10 11#include <array>12#include <cassert>13#include <type_traits>14#include "test_macros.h"15 16struct NoDefault {17 TEST_CONSTEXPR NoDefault(int) {}18};19 20struct test_initialization {21 template <typename T>22 TEST_CONSTEXPR_CXX14 void operator()() const {23 // Check default initialization24 {25 std::array<T, 0> a0;26 (void)a0;27 // Before C++20, default initialization doesn't work inside constexpr for28 // trivially default constructible types. This only apply to non-empty arrays,29 // since empty arrays don't hold an element of type T.30#if TEST_STD_VER < 2031 if (!(TEST_IS_CONSTANT_EVALUATED && std::is_trivially_default_constructible<T>::value))32#endif33 {34 std::array<T, 1> a1;35 (void)a1;36 std::array<T, 2> a2;37 (void)a2;38 std::array<T, 3> a3;39 (void)a3;40 }41 42 std::array<NoDefault, 0> nodefault;43 (void)nodefault;44 }45 46 // A const empty array can also be default-initialized regardless of the type47 // it contains. For non-empty arrays, this doesn't work whenever T doesn't48 // have a user-provided default constructor.49 {50 const std::array<T, 0> a0;51 (void)a0;52 const std::array<NoDefault, 0> nodefault;53 (void)nodefault;54 }55 56 // Check direct-list-initialization syntax (introduced in C++11)57#if TEST_STD_VER >= 1158 {59 {60 std::array<T, 0> a0_0{};61 (void)a0_0;62 }63 {64 std::array<T, 1> a1_0{};65 (void)a1_0;66 std::array<T, 1> a1_1{T()};67 (void)a1_1;68 }69 {70 std::array<T, 2> a2_0{};71 (void)a2_0;72 std::array<T, 2> a2_1{T()};73 (void)a2_1;74 std::array<T, 2> a2_2{T(), T()};75 (void)a2_2;76 }77 {78 std::array<T, 3> a3_0{};79 (void)a3_0;80 std::array<T, 3> a3_1{T()};81 (void)a3_1;82 std::array<T, 3> a3_2{T(), T()};83 (void)a3_2;84 std::array<T, 3> a3_3{T(), T(), T()};85 (void)a3_3;86 }87 88 std::array<NoDefault, 0> nodefault{};89 (void)nodefault;90 }91#endif92 93 // Check copy-list-initialization syntax94 {95 {96 std::array<T, 0> a0_0 = {};97 (void)a0_0;98 }99 {100 std::array<T, 1> a1_0 = {};101 (void)a1_0;102 std::array<T, 1> a1_1 = {T()};103 (void)a1_1;104 }105 {106 std::array<T, 2> a2_0 = {};107 (void)a2_0;108 std::array<T, 2> a2_1 = {T()};109 (void)a2_1;110 std::array<T, 2> a2_2 = {T(), T()};111 (void)a2_2;112 }113 {114 std::array<T, 3> a3_0 = {};115 (void)a3_0;116 std::array<T, 3> a3_1 = {T()};117 (void)a3_1;118 std::array<T, 3> a3_2 = {T(), T()};119 (void)a3_2;120 std::array<T, 3> a3_3 = {T(), T(), T()};121 (void)a3_3;122 }123 124 std::array<NoDefault, 0> nodefault = {};125 (void)nodefault;126 }127 128 // Test aggregate initialization129 {130 {131 std::array<T, 0> a0_0 = {{}};132 (void)a0_0;133 }134 {135 std::array<T, 1> a1_0 = {{}};136 (void)a1_0;137 std::array<T, 1> a1_1 = {{T()}};138 (void)a1_1;139 }140 {141 std::array<T, 2> a2_0 = {{}};142 (void)a2_0;143 std::array<T, 2> a2_1 = {{T()}};144 (void)a2_1;145 std::array<T, 2> a2_2 = {{T(), T()}};146 (void)a2_2;147 }148 {149 std::array<T, 3> a3_0 = {{}};150 (void)a3_0;151 std::array<T, 3> a3_1 = {{T()}};152 (void)a3_1;153 std::array<T, 3> a3_2 = {{T(), T()}};154 (void)a3_2;155 std::array<T, 3> a3_3 = {{T(), T(), T()}};156 (void)a3_3;157 }158 159 // See http://wg21.link/LWG2157160 std::array<NoDefault, 0> nodefault = {{}};161 (void)nodefault;162 }163 }164};165 166// Test construction from an initializer-list167TEST_CONSTEXPR_CXX14 bool test_initializer_list() {168 {169 std::array<double, 3> const a3_0 = {};170 assert(a3_0[0] == double());171 assert(a3_0[1] == double());172 assert(a3_0[2] == double());173 }174 {175 std::array<double, 3> const a3_1 = {1};176 assert(a3_1[0] == double(1));177 assert(a3_1[1] == double());178 assert(a3_1[2] == double());179 }180 {181 std::array<double, 3> const a3_2 = {1, 2.2};182 assert(a3_2[0] == double(1));183 assert(a3_2[1] == 2.2);184 assert(a3_2[2] == double());185 }186 {187 std::array<double, 3> const a3_3 = {1, 2, 3.5};188 assert(a3_3[0] == double(1));189 assert(a3_3[1] == double(2));190 assert(a3_3[2] == 3.5);191 }192 193 return true;194}195 196struct Empty {};197struct Trivial {198 int i;199 int j;200};201struct NonTrivial {202 TEST_CONSTEXPR NonTrivial() {}203 TEST_CONSTEXPR NonTrivial(NonTrivial const&) {}204};205struct NonEmptyNonTrivial {206 int i;207 int j;208 TEST_CONSTEXPR NonEmptyNonTrivial() : i(22), j(33) {}209 TEST_CONSTEXPR NonEmptyNonTrivial(NonEmptyNonTrivial const&) : i(22), j(33) {}210};211 212template <typename F>213TEST_CONSTEXPR_CXX14 bool with_all_types() {214 F().template operator()<char>();215 F().template operator()<int>();216 F().template operator()<long>();217 F().template operator()<float>();218 F().template operator()<double>();219 F().template operator()<long double>();220 F().template operator()<Empty>();221 F().template operator()<Trivial>();222 F().template operator()<NonTrivial>();223 F().template operator()<NonEmptyNonTrivial>();224 return true;225}226 227// This is a regression test -- previously, libc++ would implement empty arrays by228// storing an array of characters, which means that the array would be initializable229// from nonsense like an integer (or anything else that can be narrowed to char).230#if TEST_STD_VER >= 20231template <class T>232concept is_list_initializable_int = requires {233 { T{123} };234};235 236struct Foo {};237static_assert(!is_list_initializable_int<std::array<Foo, 0>>);238static_assert(!is_list_initializable_int<std::array<Foo, 1>>);239#endif240 241int main(int, char**) {242 with_all_types<test_initialization>();243 test_initializer_list();244#if TEST_STD_VER >= 14245 static_assert(with_all_types<test_initialization>(), "");246 static_assert(test_initializer_list(), "");247#endif248 249 return 0;250}251