1

Consider the following example:

template <class T> 
void f(const T&&) { std::cout << __PRETTY_FUNCTION__; };

int main(void){

       const int *cptr = nullptr;
       f(std::move(cptr));
}

Per [temp.deduct.call]/1:

Template argument deduction is done by comparing each function template parameter type (call it P) that contains template-parameters that participate in template argument deduction with the type of the corresponding argument of the call (call it A) [..]

and [temp.deduct.call]/3:

If P is a cv-qualified type, the top-level cv-qualifiers of P's type are ignored for type deduction. If P is a reference type, the type referred to by P is used for type deduction.

Considering the given paragraphs, I'm deducing the template argument for T to be int* as follows:

P = const T&&, A = const int*; // replacing 'const T&&' with 'const T'
P = const T, A = const int*
T = int*

// what's wrong with these steps?

But when I compile this code with gcc and clang, it shows that the deduced T is const int*

My Question: Why the deduced template argument is const int* and not int* as I expect?

mada
  • 1,646
  • 1
  • 15
  • There is a top-level const in `P = const T` but there is a low-level const in `A = const int*`. You can't compare them directly that way you did. Here, this means `T` will be deduced as `const int*` and the function parameter will be `const int *const &&`. – Jason Aug 16 '22 at 07:41
  • Does this answer your question? [Where is the definition of \`top-level cv-qualifiers\` in the C++11 Standard?](https://stackoverflow.com/questions/24676824/where-is-the-definition-of-top-level-cv-qualifiers-in-the-c11-standard) – Language Lawyer Aug 16 '22 at 07:45
  • @JasonLiam I can understand what you're saying as follows. In `P = const T, A = const int*` the deduction fails because `P` has top-level const and `A` has low-level const. Then the rule [temp.deduct.call#(4.1)](https://timsong-cpp.github.io/cppwp/n4861/temp.deduct#call-4.1) applies? – mada Aug 16 '22 at 07:50
  • @John Yes, like similar to explained [here](https://stackoverflow.com/a/73338000/12002570). – Jason Aug 16 '22 at 07:54
  • @John No, you can compare `P = const T` with `A = int *const` because both of these have top level const. And deduced `T` will be `int*` in this case. Note, i am not talking about this current question but replying to your last comment where you have `A = int* const` instead of `A = coinst int*`. The answer to the current question is given [below](https://stackoverflow.com/a/73370439/12002570). – Jason Aug 16 '22 at 08:24

1 Answers1

0

Why the deduced template argument is const int* and not int* as I expect?

The const in P = const T is a top level const and applies to T while the const in A = const int* is a low-level const meaning it does not apply to the pointer. This in turn means that you can't directly compare const T with const int* the way you have done.

Therefore, T will be deduced as the simplest argument type const int* and the function parameter will be of type const int *const &&.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • Am I assuming you mean that `P = const T, A = const int*` **causes** deduction failure, so [alternative deductions](https://timsong-cpp.github.io/cppwp/n4861/temp.deduct#call-4) are considered. Right? – mada Aug 16 '22 at 08:26
  • @John In this example, the deduced `A=const int*const` is more cv qualified than the transformed `A=const int*`. – Jason Aug 16 '22 at 08:29
  • 1
    @John See my updated comment above. I do think that here the the deduced `A=const int*const` is more cv qualified than the transformed `A=const int*` – Jason Aug 16 '22 at 08:33
  • _"In this example, the `deduced A=const int*const` is more cv-qualified than the `transformed A=const int*`"_ Therefore, I can compare `P` with the `deduced A` such `P = const T, deduced A = const int *const`, then `deduced T` is `const int*`. Right? – mada Aug 16 '22 at 08:38
  • @John Yes, the problem was that you were comparing them incorrectly which is why i wrote *"can't directly compare `const T` with `const int*` **the way you have done**"* in my answer. That is, yes we can compare but the conclusion that you were getting that `T` should be `int*` instead of `const int*` was incorrect. – Jason Aug 16 '22 at 08:41
  • Thanks!. But I just need to understand something. Are the rules of template argument deduction applied once in the P/A pair? I mean, why we can apply the rules again on `P` and `deduced A`? – mada Aug 16 '22 at 08:50
  • .. so `P = const T, deduced A = const int *const`. Per [para 2](https://timsong-cpp.github.io/cppwp/n4861/temp.deduct#call-2), since `P` is not of reference type, A's top-level const are ignored, then P's top-level const is ignored per [para 3](https://timsong-cpp.github.io/cppwp/n4861/temp.deduct#call-3). Therefore we have `P = T, A = const int *` then `deduced T` will be `const int*` – mada Aug 16 '22 at 08:55
  • @John What do you mean by "again". I mean it is the same P/A pair which is just transformed according to the rules given by the standard like `const T&&` adjusted to `const T` etc. And then at the end of this process(after all the changes/adjustments of the P/A pair) the result is what we use. – Jason Aug 16 '22 at 08:56
  • Simply I mean, instead of having this pair: `P = const T, deduced A = const int *const` . I am applying the rules again so that we have instead: `P = T, A = const int *`. That's what I mean by "why we cannot apply the rules again on P and deduced A" – mada Aug 16 '22 at 08:58
  • @John I see, but i don't think that is the case because note that you already have the deduced `A = const int *const` which means you already have the transformed `A = const int*`. There is no need to apply the rules again with `P = T` and `A = const int*`. – Jason Aug 16 '22 at 09:02
  • @John I also think that, that whole section describing this deduction process could have been more clearly written/described in the standard. – Jason Aug 16 '22 at 09:04