Date: Sun, 11 Oct 2020 11:36:06 -0400
On Sun, Oct 11, 2020 at 10:16 AM Григорий Шуренков via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> C++ has rather complex name lookup rules for unqualified function calls
> that involve argument-dependent lookup and may lead to surprising results.
> And from time to time there appear proposals to fix those rules. This is
> one of such proposals.
>
> Most of the time invoking ADL is not what a user wanted. However, ADL also
> has legitimate use cases: operators and "customization points" (swap,
> begin, end are examples). The idea of the proposal is that we can mark
> customization points with *operator* keyword and deprecate ADL for all
> functions that are not marked with such keyword.
>
> That is if ADL was triggered for an unqualified function call and a
> function was found via ADL that was not an *operator, *then a compiler
> may issue a warning. Currently it's not feasible to have such a warning,
> because we cannot not discriminate between "good" ADL and "bad" ADL.
>
I like this general user experience; it sounds very similar to `override`.
But then wouldn't it make more sense to introduce a contextual keyword
similar to `override`?
void swap(A& fst, A& snd) adl { ... }
One difficulty you might have with this is that you'll have to specify what
happens in a case like
void swap(A& fst, A& snd);
void swap(A& fst, A& snd) adl; // valid to add the keyword later?
void swap(A& fst, A& snd) adl { ... } // valid to repeat the keyword
later?
We don't have this problem for `explicit` and `override` and `final`
because they are usable only on member functions, which must have a single
declaration (inside the class body) and a single definition.
We don't have this problem for `noexcept` and `const` because they are part
of the type system.
We do have this problem for `static`, and I would guess that you should
copy whatever `static` does.
Declaration of a custom swap function then will look like this:
> void operator swap (A& fst, A& snd);
>
Your reuse of existing keyword `operator` smells to me like it's going to
cause parsing problems.
struct S {
operator foo(); // conversion function
void operator foo(); // member function with the ADL marker — is
this even valid?
static void operator foo(); // static member function with the ADL
marker — is this even valid?
friend void operator foo(); // friend with the ADL marker
};
void operator operator+(S); // free function with the ADL marker
void operator-(S); // free function without the ADL marker — you imply
that the ADL marker would be implicitly added anyway?
If you're going to add a contextual marker for ADL, my kneejerk reaction is
that I'd prefer it also provide some symmetric way to mark a function
(operator or otherwise) as *not *findable via ADL.
However, that might be hard because of how ADL works. The biggest practical
problem with ADL is not that it sometimes *finds *unexpected best-matches
(although that is a minor problem). The biggest problem is that it *looks *for
them in the first place. The *lookup *is the thing that can trigger hard
un-SFINAE-able errors. The lookup is the thing that produces a huge
candidate set and then spends lots of compile-time eliminating candidates.
Your proposal seems user-friendly, and seems like it provides backwards
compatibility similar to `override`, *but *it doesn't seem like it would
help at all with the problem of `operator<<` taking forever to do overload
resolution.
There are other things that might be included in the proposal:
> 1) requesting ADL via operator keyword at the call-site: operator swap(a,
> b);
> 2) searching "operator functions" among class members, thus allowing
> uniform function call syntax at least for them.
> But before exploring those directions further I would like to get feedback
> on the main idea.
>
FYI, (1) seems like a non-starter unless you can solve the parsing problem.
`operator swap();` is already valid C++ syntax.
(With some fun implementation divergence there! https://godbolt.org/z/GKb756
)
HTH,
Arthur
std-proposals_at_[hidden]> wrote:
> C++ has rather complex name lookup rules for unqualified function calls
> that involve argument-dependent lookup and may lead to surprising results.
> And from time to time there appear proposals to fix those rules. This is
> one of such proposals.
>
> Most of the time invoking ADL is not what a user wanted. However, ADL also
> has legitimate use cases: operators and "customization points" (swap,
> begin, end are examples). The idea of the proposal is that we can mark
> customization points with *operator* keyword and deprecate ADL for all
> functions that are not marked with such keyword.
>
> That is if ADL was triggered for an unqualified function call and a
> function was found via ADL that was not an *operator, *then a compiler
> may issue a warning. Currently it's not feasible to have such a warning,
> because we cannot not discriminate between "good" ADL and "bad" ADL.
>
I like this general user experience; it sounds very similar to `override`.
But then wouldn't it make more sense to introduce a contextual keyword
similar to `override`?
void swap(A& fst, A& snd) adl { ... }
One difficulty you might have with this is that you'll have to specify what
happens in a case like
void swap(A& fst, A& snd);
void swap(A& fst, A& snd) adl; // valid to add the keyword later?
void swap(A& fst, A& snd) adl { ... } // valid to repeat the keyword
later?
We don't have this problem for `explicit` and `override` and `final`
because they are usable only on member functions, which must have a single
declaration (inside the class body) and a single definition.
We don't have this problem for `noexcept` and `const` because they are part
of the type system.
We do have this problem for `static`, and I would guess that you should
copy whatever `static` does.
Declaration of a custom swap function then will look like this:
> void operator swap (A& fst, A& snd);
>
Your reuse of existing keyword `operator` smells to me like it's going to
cause parsing problems.
struct S {
operator foo(); // conversion function
void operator foo(); // member function with the ADL marker — is
this even valid?
static void operator foo(); // static member function with the ADL
marker — is this even valid?
friend void operator foo(); // friend with the ADL marker
};
void operator operator+(S); // free function with the ADL marker
void operator-(S); // free function without the ADL marker — you imply
that the ADL marker would be implicitly added anyway?
If you're going to add a contextual marker for ADL, my kneejerk reaction is
that I'd prefer it also provide some symmetric way to mark a function
(operator or otherwise) as *not *findable via ADL.
However, that might be hard because of how ADL works. The biggest practical
problem with ADL is not that it sometimes *finds *unexpected best-matches
(although that is a minor problem). The biggest problem is that it *looks *for
them in the first place. The *lookup *is the thing that can trigger hard
un-SFINAE-able errors. The lookup is the thing that produces a huge
candidate set and then spends lots of compile-time eliminating candidates.
Your proposal seems user-friendly, and seems like it provides backwards
compatibility similar to `override`, *but *it doesn't seem like it would
help at all with the problem of `operator<<` taking forever to do overload
resolution.
There are other things that might be included in the proposal:
> 1) requesting ADL via operator keyword at the call-site: operator swap(a,
> b);
> 2) searching "operator functions" among class members, thus allowing
> uniform function call syntax at least for them.
> But before exploring those directions further I would like to get feedback
> on the main idea.
>
FYI, (1) seems like a non-starter unless you can solve the parsing problem.
`operator swap();` is already valid C++ syntax.
(With some fun implementation divergence there! https://godbolt.org/z/GKb756
)
HTH,
Arthur
Received on 2020-10-11 10:36:21