On Thu, 13 Mar 2025 at 21:54, Jonathan Wakely <jwak...@redhat.com> wrote: > > On Thu, 13 Mar 2025 at 21:29, Patrick Palka <ppa...@redhat.com> wrote: > > > > On Thu, 13 Mar 2025, Ville Voutilainen wrote: > > > > > On Thu, 13 Mar 2025 at 23:16, Ville Voutilainen > > > <ville.voutilai...@gmail.com> wrote: > > > > > > > > On Thu, 13 Mar 2025 at 23:03, Patrick Palka <ppa...@redhat.com> wrote: > > > > > + // Defined as a template to work around PR libstdc++/116440. > > > > > + template<class...> > > > > > + constexpr explicit(!__convertible<const _Elements&...>()) > > > > > + tuple(const _Elements&... __elements) > > > > > > > > I don't understand how a constructor template declared like this can > > > > ever be called. The template parameter pack > > > > can't be provided or deduced, and can't have a default. So we're > > > > effectively making this signature always lose > > > > overload resolution to the one that takes a pack of _UElements&&. > > > > > > > > Which may be fine. I can't head-compile a test that would fail in that > > > > case. If any of the incoming argument isn't one > > > > of _Elements, that constructor wins overload resolution anyway. If the > > > > incoming arguments are exactly _Elements, that > > > > constructor does the same thing as this one. I think. > > > > > > Oh, never mind. The pack is just deduced as an empty pack. > > > > Yep that's my understanding, though I don't know where in the standard > > this is specified, a quick Ctrl+F is failing me. > > > > I can use template<int = 0> or template<typename = void> if that's > > preferred :) > > I would prefer template<typename = void> to the empty pack, I think > the default template argument makes it a little more obvious how that > constructor can be called (I'm sure Ville won't be the only one to > raise an eyebrow at that). > > Thanks for figuring this out, and noticing that that the template-ness > of that constructor is what changed between C++17 and C++20. I think > when I re-implemented it using concepts I assumed the template-ness > was there for the _ImplicitCtor / _ExplicitCtor stuff, which is done > using explicit(bool) in C++20. I wasn't looking at the tuple(const > _Elements&...) constructor at all, because the errors all pointed to > tuple(_UTypes&&...). > > Do we also want to constraint the tuple(const _Elements&...) > constructor with requires sizeof...(_Elements) >= 1, which is present > on the C++17 version?
Oh we don't need that constraint, because we have an explicit specialization for tuple<>.