@@ -172,6 +172,16 @@ private:
172172 }
173173 }
174174
175+ template <typename T, size_t... Is>
176+ constexpr storage_type _impl_converting_constructor(T&& o, std::index_sequence<Is...>) {
177+ return {([&]()->Types... [Is] {
178+ if constexpr (std::is_reference_v<Types...[Is]>)
179+ return o.template get<Is>();
180+ else
181+ return Types... [Is] { std::forward_like<T>(o.template get<Is>()) };
182+ }())...};
183+ }
184+
175185public:
176186 storage_type _impl_storage;
177187 static constexpr auto _impl_accessor = [:_impl::cache_members(nonstatic_data_members_of(
@@ -190,64 +200,95 @@ public:
190200 // sizeof...(Types) >= 1;
191201
192202 // [tuple.cnstr], tuple construction
193- constexpr explicit((!_tuple_impl::is_implicitly_default_constructible<Types> || ...))
203+ constexpr explicit((!_tuple_impl::is_implicitly_default_constructible<Types> ||
204+ ...)) // [tuple.cnstr]/8
194205 tuple() noexcept(std::is_nothrow_default_constructible_v<storage_type>)
195- requires(std::is_default_constructible_v<storage_type>)
206+ requires(sizeof...(Types) >= 1 &&
207+ std::is_default_constructible_v<storage_type>) // [tuple.cnstr]/6
196208 = default;
197209
198- constexpr explicit(!(std::is_convertible_v<Types const&, Types> && ...))
210+ constexpr tuple() noexcept
211+ requires(sizeof...(Types) == 0)
212+ = default; // [tuple.cnstr]/5
213+
214+ constexpr explicit(!(std::is_convertible_v<Types const&, Types> && ...)) // [tuple.cnstr]/11
199215 tuple(Types const&... values) noexcept((std::is_nothrow_copy_constructible_v<Types> && ...))
200- requires(sizeof...(Types) >= 1 && (std::is_copy_constructible_v<Types> && ...))
216+ requires(sizeof...(Types) >= 1 &&
217+ (std::is_copy_constructible_v<Types> && ...)) // [tuple.cnstr]/9
201218 : _impl_storage{values...} {}
202219
203220 template <class... UTypes>
204- requires(sizeof...(UTypes) == sizeof...(Types) &&
205- !(std::reference_constructs_from_temporary_v<Types, UTypes &&> ||
206- ...) && // TODO required?
221+ requires(sizeof...(UTypes) == sizeof...(Types) && // [tuple.cnstr]/13.1
222+ sizeof...(UTypes) >= 1 && // [tuple.cnstr]/13.2
207223 enable_utypes_ctor<UTypes...> &&
208- (std::is_constructible_v<Types, UTypes> && ...))
209- constexpr explicit(!(std::is_convertible_v<UTypes, Types> && ...)) tuple(UTypes&&... values)
224+ (std::is_constructible_v<Types, UTypes> && ...)) // [tuple.cnstr]/13.3
225+ constexpr explicit(!(std::is_convertible_v<UTypes, Types> && ...)) // [tuple.cnstr]/15
226+ tuple(UTypes&&... values)
210227 : _impl_storage(std::forward<UTypes>(values)...) {}
211228
212229 template <class... UTypes>
213230 requires(sizeof...(UTypes) == sizeof...(Types) &&
214- (std::reference_constructs_from_temporary_v<Types, UTypes &&> || ...))
231+ (std::reference_constructs_from_temporary_v<Types, UTypes &&> || // [tuple.cnstr]/15
232+ ...))
215233 constexpr tuple(UTypes&&... values) = delete;
216234
217- tuple(tuple const&) noexcept(std::is_nothrow_copy_constructible_v<storage_type>)
218- requires(std::is_copy_constructible_v<storage_type>)
235+ constexpr tuple(tuple const&) noexcept(std::is_nothrow_copy_constructible_v<storage_type>)
236+ requires(std::is_copy_constructible_v<storage_type>) // [tuple.cnstr]/16
219237 = default;
220238
221- tuple(tuple&&) noexcept(std::is_nothrow_move_constructible_v<storage_type>)
222- requires(std::is_move_constructible_v<storage_type>)
239+ constexpr tuple(tuple&&) noexcept(std::is_nothrow_move_constructible_v<storage_type>)
240+ requires(std::is_move_constructible_v<storage_type>) // [tuple.cnstr]/18
223241 = default;
224242
225243 template <class... UTypes>
226- constexpr explicit(!(std::is_convertible_v<UTypes&, Types> && ...))
244+ requires(sizeof...(UTypes) == sizeof...(Types)) && // [tuple.cnstr]/21.1
245+ (std::is_constructible_v<Types, UTypes&> && ...) && // [tuple.cnstr]/21.2
246+ (sizeof...(UTypes) != 1 || // [tuple.cnstr]/21.3
247+ (!std::is_convertible_v<tuple<UTypes...>, Types...[0]> && // [tuple.cnstr]/21.3
248+ !std::is_constructible_v<Types...[0], tuple<UTypes...>> && // [tuple.cnstr]/21.3
249+ !std::same_as<Types...[0], UTypes...[0]>)) // [tuple.cnstr]/21.3
250+ constexpr explicit(!(std::is_convertible_v<UTypes&, Types> && ...)) // [tuple.cnstr]/23
227251 tuple(tuple<UTypes...>& other) noexcept((std::is_nothrow_constructible_v<Types, UTypes&> &&
228252 ...))
229- requires(false) // TODO
230- : _impl_storage(other) {}
253+ : _impl_storage(_impl_converting_constructor(other, std::index_sequence_for<Types...>{})) {}
231254
232255 template <class... UTypes>
233- constexpr explicit(!(std::is_convertible_v<UTypes const&, Types> && ...))
256+ requires(sizeof...(UTypes) == sizeof...(Types)) && // [tuple.cnstr]/21.1
257+ (std::is_constructible_v<Types, UTypes&> && ...) && // [tuple.cnstr]/21.2
258+ (sizeof...(UTypes) != 1 || // [tuple.cnstr]/21.3
259+ (!std::is_convertible_v<tuple<UTypes...>, Types...[0]> && // [tuple.cnstr]/21.3
260+ !std::is_constructible_v<Types...[0], tuple<UTypes...>> && // [tuple.cnstr]/21.3
261+ !std::same_as<Types...[0], UTypes...[0]>)) // [tuple.cnstr]/21.3
262+ constexpr explicit(!(std::is_convertible_v<UTypes&, Types> && ...)) // [tuple.cnstr]/23
234263 tuple(tuple<UTypes...> const& other) noexcept(
235- (std::is_nothrow_constructible_v<Types, UTypes const&> && ...))
236- requires(false) // TODO
237- : _impl_storage(other) {}
264+ (std::is_nothrow_constructible_v<Types, UTypes&> && ...))
265+ : _impl_storage(_impl_converting_constructor(other, std::index_sequence_for<Types...>{})) {}
238266
239267 template <class... UTypes>
240- constexpr explicit(!(std::is_convertible_v<UTypes, Types> && ...))
241- tuple(tuple<UTypes...>&& other) noexcept((std::is_nothrow_constructible_v<Types, UTypes> &&
268+ requires(sizeof...(UTypes) == sizeof...(Types)) && // [tuple.cnstr]/21.1
269+ (std::is_constructible_v<Types, UTypes &&> && ...) && // [tuple.cnstr]/21.2
270+ (sizeof...(UTypes) != 1 || // [tuple.cnstr]/21.3
271+ (!std::is_convertible_v<tuple<UTypes...>, Types...[0]> && // [tuple.cnstr]/21.3
272+ !std::is_constructible_v<Types...[0], tuple<UTypes...>> && // [tuple.cnstr]/21.3
273+ !std::same_as<Types...[0], UTypes...[0]>)) // [tuple.cnstr]/21.3
274+ constexpr explicit(!(std::is_convertible_v<UTypes&&, Types> && ...)) // [tuple.cnstr]/23
275+ tuple(tuple<UTypes...>&& other) noexcept((std::is_nothrow_constructible_v<Types, UTypes&> &&
242276 ...))
243- requires(false) // TODO
244- : _impl_storage (std::move(other)) {}
277+ : _impl_storage(
278+ _impl_converting_constructor (std::move(other), std::index_sequence_for<Types...>{} )) {}
245279
246280 template <class... UTypes>
247- constexpr explicit(!(std::is_convertible_v<UTypes, Types> && ...))
248- tuple(tuple<UTypes...> const&& other)
249- requires(false) // TODO
250- : _impl_storage(std::move(other)) {}
281+ requires(sizeof...(UTypes) == sizeof...(Types)) && // [tuple.cnstr]/21.1
282+ (std::is_constructible_v<Types, UTypes &&> && ...) && // [tuple.cnstr]/21.2
283+ (sizeof...(UTypes) != 1 || // [tuple.cnstr]/21.3
284+ (!std::is_convertible_v<tuple<UTypes...>, Types...[0]> && // [tuple.cnstr]/21.3
285+ !std::is_constructible_v<Types...[0], tuple<UTypes...>> && // [tuple.cnstr]/21.3
286+ !std::same_as<Types...[0], UTypes...[0]>)) // [tuple.cnstr]/21.3
287+ constexpr explicit(!(std::is_convertible_v<UTypes&&, Types> && ...)) // [tuple.cnstr]/23
288+ tuple(tuple<UTypes...> const&& other) noexcept(
289+ (std::is_nothrow_constructible_v<Types, UTypes&> && ...))
290+ : _impl_storage(
291+ _impl_converting_constructor(std::move(other), std::index_sequence_for<Types...>{})) {}
251292
252293 // template <class U1, class U2>
253294 // constexpr explicit(true /* TODO*/) tuple(std::pair<U1, U2>&); // only if
0 commit comments