14

In 14.8.2.4p10 of the C++11 draft, there is written

If for each type being considered a given template is at least as specialized for all types and more specialized for some set of types and the other template is not more specialized for any types or is not at least as specialized for any types, then the given template is more specialized than the other template.

Why is there a "or is not at least as specialized for any types"? As far as I can see, if we have a list of types

T1, T2, T3
U1, U2, U3

And if all Ts are at least as specialized and some are more specialized. And none of the Us are more specialized, then it seems to me that it follows that the set of T as a whole is more specialized than the set of U, logically speaking. Why is there then that mentioned fallback for when none of the Us are at least as specialized than the corresponding Ts?

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • I don't even get the *"and the other template is not more specialized for any types"*-part since it already says *"for each type being considered a given template is at least as specialized for all types"*, so isn't for former already included in the latter? – Daniel Frey Mar 29 '13 at 11:43
  • @DanielFrey as an analogy, a given 1 is at least as large as another 1, but another 1 is not larger than the given 1. – Johannes Schaub - litb Mar 29 '13 at 11:54
  • D'oh! Of course. I should take a break. :) – Daniel Frey Mar 29 '13 at 11:56
  • @DanielFrey: If you need a break, then I might need two breaks, because I have troubles understanding the analogy. I would say the real analogy should be "*a given 1 is at least as small (at least as specialized) as another 1*", which automatically implies that the other 1 is not smaller than ("more specialized than") the given 1. So I'd also say it is redundant. What am I missing? – Andy Prowl Mar 29 '13 at 12:31
  • @Daniel Frey - After reading this paragraph of the our great Standard i feel "at least ... more specialized" than most of the other people. – SChepurin Mar 29 '13 at 12:43
  • @AndyProwl: I take back my "D'oh! Of course." and I go back to being confused. The analogy already shows my problem: If x>=x', it implies !(x'>x). At least I don't feel alone with that anymore. :) What the hell is going on in that paragraph??? (Great question, Johannes!) – Daniel Frey Mar 29 '13 at 12:44
  • 7
    @DanielFrey: I just can't figure out why they do not formalize this stuff and express it directly in some first-order logics rather than (or at least in addition to) writing it in English. It would not be more complicated, and it would definitely be less ambiguous. I mean, this looks like reading the original version of Euclid's Elements, with no symbolic names for geometric entities. Why on earth does it have to be *so* painful every time? – Andy Prowl Mar 29 '13 at 12:51
  • @JohannesSchaub-litb: Btw, +1 – Andy Prowl Mar 29 '13 at 12:51
  • 4
    @AndyProwl: And now imagine how hard it is for us non-native speakers ;( – Daniel Frey Mar 29 '13 at 12:53
  • 3
    @DanielFrey: I guess we're all non-native speakers here ;) – Andy Prowl Mar 29 '13 at 12:56
  • @AndyProwl I agree my analogy was fail. It just confused me all the way down. In the partial ordering paragraphs, as soon as a deduction of A against B works, A is considered at least as specialized as B. If it later turns out that B against A fails, B is not at least as specialized as A. I think the question is whether we are now allowed to follow the laws of logics and say that A is more specialized than B. If however B against A works too, B too is at least as specialized than A. Now with the laws of logics, each is equally specialized than the other. – Johannes Schaub - litb Mar 29 '13 at 14:14
  • ... but if both are reference types, there is another set of rules that then make either B or A more specialized. So it can happen that although A is at least as specialized as B, B can still be more specialized than A for some parameter, if both types are reference types and some condition is met. – Johannes Schaub - litb Mar 29 '13 at 14:15
  • @JohannesSchaub-litb: I might have to read through the Standard a bit more to be aligned with you, but I would say there are two degrees of "equivalence": when two templates, for a given type, are "equally specialized" then I guess one can be matched against the other, and vice versa. Then there is the situation where none of them can be matched against the other. Maybe this nuances matter in determining the meaning of "at least as specialized". Hope I'm not writing non-sense, just reasoning aloud. – Andy Prowl Mar 29 '13 at 14:18
  • 1
    @JohannesSchaub-litb: Hm, maybe we just [need brackets](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#425) in natural language? What *part* of the paragraph is the "or" refering to (for your original question)? I know I have been fooled by this more than once in the Standard. – Daniel Frey Mar 29 '13 at 14:22
  • @DanielFrey: I believe it is "*for each type being considered **(** a given template is at least as specialized for all types and more specialized for some set of types **)** and **(** the other template is not more specialized for any types or is not at least as specialized for any types **)***" – Andy Prowl Mar 29 '13 at 14:37

2 Answers2

7

Update: This has now been added as an official C++ Issue


I have finally figured out how to read the paragraph in question. Below I have bulleted it

If for each type being considered a given template is at least as specialized for all types, and

  • more specialized for some set of types and the other template is not more specialized for any types, or
  • {the other template} is not at least as specialized for any types,

then the given template is more specialized than the other template.

This way the following first template is also more specialized than the second template

template<typename T> void f(T*);
template<typename T> void f(T);

Note that the first template's parameter is at least as specialized as the second template, but is not defined to be "more specialized" - that term only applies for the case where both parameters were references and certain conditions apply (see paragraph 9 of 14.8.2.4) . The rules are apparently not meant to follow any formal ordering laws. The second template is not at least as specialized as the first template. This means that the second bullet applies, and not the first.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Could you ***please*** write a DR so they clarify this sentence for future generations? I actually like the idea using bullet points as shown above, so much easier! – Daniel Frey Mar 29 '13 at 20:59
6

This answer is based on an incorrect parsing of the Standard paragraph's abstract syntax tree. The grouping of conditions assumed in the "Back to the Standard" section turned out not to be the intended one. The intended grouping is the one Johannes Schaub has shown in his answer.


Why is there then that mentioned fallback for when none of the Us are at least as specialized than the corresponding Ts?

I agree with you that the second part (actually, the whole second condition) is redundant.


Some vocabulary of reference:

Let's have some fun with logics and introduce 3 fundamental relations between two templates for a pair of corresponding parameters:

  • More specialized than: for parameters Ti and Ui respectively, one template matches the other but not vice versa. I will indicate this as Ti < Ui;
  • Equally specialized: for parameters Ti and Ui respectively, one template matches the other and vice versa. I will indicate this as Ti == Ui;
  • Specialization-incomparable: for parameters Ti and Ui respectively, none of the templates matches the other for the particular parameter. I will indicate this as T1 ~ U1.

For instance, in the code snippet below:

template<typename X> struct A { };
template<typename X> struct B { };

template<typename X> void foo(A<X>, X, A<X>) { } // 1
template<typename X> void foo(X,    X, B<X>) { } // 2

For the first parameter, (1) is more specialized than (<) (2); for the second parameter, (1) is equally specialized as (or "as specialized as", ==) (2); for the third parameter, (1) is specialization-incomparable to (~) (2).

And let' now define a derived relation:

  • A template (1) is at least as specialized as another template (2) for respective parameters Ti and Ui when (Ti < Ui) or (Ti == Ui), i.e. when either (1) is more specialized than (2) or (1) is as specialized as (2). In the above example, therefore, T1 <= U1, T2 <= U2, and U2 <= T2.

Back to the Standard:

With the help of a couple of parentheses, the quote above becomes (A && (B1 || B2)):

[...] for each type being considered:

( a given template is at least as specialized for all types and more specialized for some set of types )

                                 AND 

( the other template is not more specialized for any types

                                 OR

is not at least as specialized for any types )

Given two templates to be ordered with respect to the corresponding sequences of parameter types T1, ..., Tn and U1, ..., Un, the condition (A):

[...] a given template is at least as specialized for all types and more specialized for some set of types [...]

Means that for each i = 1..n, Ti <= Ui, and for some js in 1..n, it applies the stricter condition that Tj < Uj. Dropping the index i, this means that for each parameter:

(T < U) || (T == U) // (A)

This condition is put in logical conjunction ("and") with another condition (B), which is in turn the logical disjunction ("or") of two sub-conditions, (B1) and (B2). Let's start examining sub-condition (B1):

[...] the other template is not more specialized for any types [...]

This means that for any i, it is never the case that Ui < Ti, which means that either:

  • Ti is more specialized than Ui (Ti < Ui); or
  • Ti and Ui are equally specialized (Ui == Ti); or
  • Ti and Ui are specialization-incomparable (Ui ~ Ti):

More formally:

!(U < T) <==> (T < U) || (T == U) || (T ~ U) // (B1)

Now let's see the second sub-condition (B2), which is put in logical disjunction with (B1):

[...] is not at least as specialized for any types [...]

This is the negation of U <= T, which means:

!(U <= T) <==> !((U == T) || (U < T)) ==> !(U == T) && !(U < T)

So in other words, T and U are not equally-specialized, nor U is more specialized than T. Therefore, the only possibilities left are that:

(T < U) || (T ~ U) // (B2)

Now it is evident that (B2) implies (B1), because (B2) is more restrictive. Therefore, their disjunct (B) will be coincident with (B1), and (B2) is redundant:

(T < U) || (T ~ U) || (T == U) // (B)

But what is also evident here is that (A) is stricter than (B), so the conjunction of (A) and (B) is equivalent to (A).


Conclusion:

The whole condition (B) is redundant.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • The sentence "(B1) implies (B2)" should read "(B2) implies (B1)". (I can't edit it because the change has less than 6 chars). – Cassio Neri Mar 29 '13 at 17:43
  • Hmm according to the Standards, for `template void f(T&&); template void f(T&);`, the first template's first parameter is at last as specialized as the second, and the second's is at least as specialized as the first (because deduction matches in each direction). But the parameter of the second template is more specialized (because it is an lvalue reference while the one of the first is an rvalue reference). Therefor I think applying logics of ordering is not the right approach - it has its own set of rules. These rules make the first part of the condition possible. – Johannes Schaub - litb Mar 29 '13 at 17:57
  • @JohannesSchaub-litb: I find it more likely that you are on the right track, and in fact this answer is kind of an invitation to spot the logical mistake and put things in more formal terms, so that it's easier to figure out where one's logical reasoning path breaks. I mean, I do not *really* believe the committee wrote such a sentence, half of which would be redundant under my interpretation, without meaning something subtly different. But they didn't give a clue on how to interpret it, so as C++ apprentice I'm left with nothing else than my attempts to follow a logical path. – Andy Prowl Mar 29 '13 at 18:05
  • @AndyProwl ah I see. I appreciate your writeup. I'm sure it's helpful to find out what's going on. thanks so much! I guess I won't sleep tonight until I found out what's going on – Johannes Schaub - litb Mar 29 '13 at 18:09
  • @JohannesSchaub-litb: You're welcome, I hope you'll figure it out, because I'm curious as well. There are actually many holes in my knowledge, and I believe I can't help further than this without at least a thorough read of Clause 14 - which will take me longer than it will take you to figure out what's wrong. – Andy Prowl Mar 29 '13 at 18:14
  • @JohannesSchaub-litb: Btw, when you say the second template is more specialized because the parameter type is an lref vs an rref, why is that the case? This is interesting and seems to be a possible key to solve the problem – Andy Prowl Mar 29 '13 at 18:18
  • Interesting that the paper this is based on, http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1393.html, did not contain the weird paragraph yet. It was added apparently when the paper was incorporated into the working draft by the core group, see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#214 at the end. – Johannes Schaub - litb Mar 29 '13 at 18:19
  • @AndyProwl because of 14.8.2.4p9 – Johannes Schaub - litb Mar 29 '13 at 18:20
  • @JohannesSchaub-litb: OK, thank you for the information. Actually it seems that the definition of "at least as specialized" is not just "(more specialized than) or (as specialized as)", as I assumed. But then the logic behind it gets weird – Andy Prowl Mar 29 '13 at 18:24
  • @Andy: My pleasure. Other remark (not worth changing anything). The argument can be simplified if you merge `~` and `==` into a single relationship (still denoted by `~`): `T ~ U <=> !(T < U) && !(U < T)`. Define `T <~ U` in the natural way (`T < U || T ~ U`) and prove that 'T <~ U <=> !(U < T)'. Then A reads `Ti <~ Ui` for all `i` with `Tj < Uj` for some `j`. Hence A implies `!(Ui < Ti)` for all `i` which is B1. Finally, B2 becomes `!(Ui <~ Ti)` for all `i` which also implies B1. – Cassio Neri Mar 29 '13 at 18:35
  • @CassioNeri: Beautiful. In fact, I was suspecting that differentiating between `~` and `==` would have been useless in the end, but when I started writing I had the feeling that the logical path might have led me somewhere where the distinction would have mattered. That did not end up being the case though. Thank you for your remark :) – Andy Prowl Mar 29 '13 at 18:38
  • @AndyProwl: No problem. Actually, I tried this logical argument before but then I stuck because I didn't know if the definition of `T <~ U`, according to the standard, was really `(T < U || T ~ U)` as I suspected (or wished). I spent several minutes reading chap 14 but couldn't figure that out. Now I see in one of your remarks that this is indeed unclear. Oh dear! Often the standard seems more complicated than it should be. – Cassio Neri Mar 29 '13 at 18:46
  • @CassioNeri: Indeed, as Johannes Schaub pointed out in the example with lvalue reference vs rvalue reference, it seems to be more complex than that. – Andy Prowl Mar 29 '13 at 18:49
  • @AndyProwl ah I think this is how we should read it, then it all makes sense: *"If for each type being considered a given template is (at least as specialized for all types) and ((more specialized for some set of types and the other template is not more specialized for any types)) or ({the other template} is not at least as specialized for any types)), then the given template is more specialized than the other template."*. The part reading *"{the other template}"* was added by me for clarity reason. – Johannes Schaub - litb Mar 29 '13 at 19:42
  • Then that also covers the case where a given template is at least as specialized for all types but not more specialized for any types as well. That is OK and suffices for it to be more specialized in sum, *if* the other template is not at least as specialized for any type. – Johannes Schaub - litb Mar 29 '13 at 19:44
  • @JohannesSchaub-litb: When I was reading it for the n-th time, for a moment I've even thought of that possibility, but then I just told to myself "nah, can't be". Well, obviously it can. Well done – Andy Prowl Mar 29 '13 at 20:29
  • Back from a break and you guys figured it out! Great job!! Actually, I was parsing the sentence differently from you, Andy, but I was also parsing it in a wrong way so it never made any sense to me. Johannes finally found the right "bracketing", so +1 for him (this answer was already helpful and had my +1). – Daniel Frey Mar 29 '13 at 20:57
  • @DanielFrey: Actually it was Johannes who figured that out even before I could think of re-grouping those sentences, so credits go to him ;) – Andy Prowl Mar 29 '13 at 21:02