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?

Reply via email to