> > Now with that out of the way, I do still kind of feel icky about it.
> > This really is a MASSIVE edge case that will almost never matter. As
> > far as I know, instantiating explicitly like so...
> > 
> > auto f = [x = 42](this auto&&) -> int { return x; };
> > int (*fp)(int&) = &decltype(f)::operator();
> > 
> > ...is the only way to coerce the explicit object parameter of the
> > lambda's call operator into deducing as an unrelated type. Cases that
> > are not deduced can be caught trivially while parsing the lambda and
> > are the only reasonable cases where you might have an unrelated type.
> > Perhaps it might become relevant in the future if a proposal like
> > https://atomgalaxy.github.io/isocpp-1107/D1107.html ever made it in,
> > but we aren't there yet. So as it stands, I'm pretty certain that it's
> > just impossible to instantiate a lambda's call operator with an
> > unrelated xobj parameter type except for the above case with
> > address-of. If you can think of another, please do share, but I've
> > spent a fair amount of time on it and came up with nothing.
> 
> 
> I think you're right.
> 
I was about to send a quick e-mail amending this, before I respond to
everything else I want to include this test case I just came up with minutes
ago.

template<typename T>
struct S : T {
  using T::operator();
  operator int() const {return {};}
};

int main()
{
  auto s0 = S{[](this auto&& self) { return self; }};
  auto s1 = S{[x = 0](this auto&& self) { return self; }};

  s0.operator()<int>();
  s1.operator()<int>();
}

So I was wrong, but, the good news is that this does demonstrate that there
is a code path where my diagnostic works.

template<typename T>
concept NotInt = (!__is_same (T, int));

template<bool> struct enable_if {};
template<> struct enable_if<true> { using type = decltype(nullptr); };
template<bool B> using enable_if_t = typename enable_if<B>::type;

template<NotInt T>
void using_concepts(T) {}

template<typename T, enable_if_t<!__is_same (T, int)> = nullptr>
void using_enable_if(T) {}

void test()
{
  void (*fp_concepts)(int) = &using_concepts;
  void (*fp_enable_if)(int) = &using_enable_if;

  using_concepts(0);
  using_enable_if(0);
}

I also have this test case that demonstrates the difference in diagnostic
quality. This is unrelated to explicit object member functions though, but
it does demonstrate that the diagnostics that I currently produce are in
equal quality to the ones already produced in these cases.

At this point I feel like I am unlikely to start fixing the bug with
captures not being treated as const tonight. Cleaning up the tests is taking
me longer than I thought.

Anyway I'm just rushing this e-mail to clarify this mistake, admittedly I am
a little excited to have found (which in hindsight should have been obvious)
a test case that more directly calls a lambda's call operator with an
unrelated type.

Alex

Reply via email to