-
Notifications
You must be signed in to change notification settings - Fork 771
[temp.func.order] Making the intent of transformations clearer #7855
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I don't see why Intuitively, if we synthesizes some types (X, X)
(Y, std::type_identity_t<Y>) ... then it seems like with either set of parameter types, we could call the other function, and deduction would succeed in the same cases, so neither is more specialized. Perhaps it would work in the following example: template <typename T> void f(T);
template <typename T> void f(std::type_identity_t<T>); // more specialized In any case, it's not obvious to me that the wording is unclear, or that the example would clarify anything. |
Here's why we think that There are two pairs of original and transformed [temp.func.order]/3 types P and A here:
In the first case, deduction fails since it would deduce conflicting arguments for Therefore, the first overload is more specialized than the second [temp.deduct.partial]/10. In your example it is correct that the second overload is more specialized than the first, but for a different reason. If we were to do the same analysis, there would be no conflicting arguments in the first case and deduction would succeed, and in the second case deduction would fail because the template parameter is only used in a non-deduced context. |
Why? The arguments are I've heard some implementations might keep those types dependent, which would explain the difference. |
As far as my understanding goes, the key here is [temp.func.order]/3 (emphasis mine):
The intention (and what all implementations seem to be doing) appears to be that only substitution into the function type is performed during production of the transformed template, no actual type is produced. In particular, no instantiation of any constituent templates takes place. Thus, whether two "types" are "the same" in this context comes down to purely the structure of the type specifiers rather than what types they actually would resolve to. The fact that the wording talks about a "transformed template" rather than a "transformed type" may also be a hint in this direction, though [temp.deduct.partial] then refers to both as types rather than templates, except where it doesn't. I believe that "type" in this context is taken to mean the type expressed in terms of the template parameters / substituted invented types; at least that's the only way I can make some sense of the wording. From what I could gather, the reasoning behind this seems to be that partial ordering should be decidable solely based on the declarations of the templates themselves. I can only guess that this is to avoid issues to do with what it would actually mean to instantiate random templates with these invented types: What is the nature of these invented types? What are valid uses of them? What happens when an instantiation with such an invented type results in an invalid construct? How would all of this interact with explicit or partial specializations? As evidenced by the reactions in this thread, this behavior is highly counter-intuitive and non-obvious from the wording, which is why we think there should at the very least be a note and example to point this out. Ideally, the wording would of course be changed to actually specify this behavior in clear terms. This issue seems to also have been brought up before in #523 and CWG 2160. |
Yeah, I've checked on CE and all big three compilers implement it so that This is worth an example. |
The wording of [temp.func.order]/3
is vague and leaves the precise nature of the transformed function type to be easily misunderstood. Consider, for example:
Intuitively, one might expect the transformed function type to be
void (A, A)
where
A
is some unique invented type. However, the intention seems to be that the transformed function type in this case becomesvoid (A, B)
where
A
andB
are distinct invented types. i.e., the transformation performs substitution only, type-specifiers that would require template instantiation to resolve are considered to give rise to distinct types of their own.We would suggest to add a note of this fact and, ideally, some examples to illustrate this key issue. e.g.:
Big thanks to @michael-kenzel for the explanation and the example.
The text was updated successfully, but these errors were encountered: