Why aren't template type parameters inferred as 'const'? [duplicate]
Asked Answered
K

2

7

Possible Duplicate:
deducing references to const from rvalue arguments

If I have

template<class T>
void foo(T &) { }

and I call it as foo((const int)5), given that the argument is a const int, why doesn't the compiler automatically infer T to be const int?

Karly answered 13/8, 2012 at 9:26 Comment(0)
F
7

It does, if it's given a const type. Rvalues (prvalues in C++11) with non-class types, however, are never cv-qualified, even if you try to say they are: the expression ((const int)5) has type int. The reasoning here is that cv-qualifications only apply to objects, and temporaries of non-class types aren't objects, but pure values; cv-qualifications can't apply, because there's nothing to be const or volatile.

If you write:

int const i = 42;
foo( i );

, your template will instantiate with T = int const. (As you wrote it, the code shouldn't compile, because the deduced type is int, so the function takes an int&, which can't be initialized with an rvalue.)

Fix answered 13/8, 2012 at 10:5 Comment(6)
Just to clarify, what exactly is the "non-class type" here that you're talking about? int or int& or const int or const int&? (I'm not sure I know the meaning of the term well enough to understand your answer yet.)Karly
Since we're talking about adding cv-qualifiers to it, the type must be int. In the original code, at least, the type would have been int const (after the cast), except that rvalues of non-class type don't have cv-modifiers. (It's interesting to note that casting to int const& should work.)Fix
Whoa, so struct Foo { }; foo((const Foo)Foo()); works fine?! I never knew that! +1 it makes absolutely no sense why int is any different from an arbitrary struct but this seems to be the correct explanation, thanks..Karly
@Mehrdad History. It makes no sense, except that in C, rvalues are never cv-qualified, and C++ wants to behave identically (although in this case, I don't see how it could matter). But whether a class type is const or not affects function overload resolution: which function you call in something like foo().bar(), for example. So cv-qualifiers have to have an impact on class types. Anyhow, that's the rationale I was given.Fix
What exactly would the difference between a normal 42 and a const 42 be?Plant
@FredOverflow The type, since const is part of the C++ type system. (Presumably, if C++ had gone this route, the type of 42 would be int const, and there would be no literal with type just int.)Fix
B
8

The type of an integer literal is int, not const int, according to C++03 Standard, clause 2.12.1.2.

The type of an integer literal depends on its form, value, and suffix. If it is decimal and has no suffix, it has the first of these types in which its value can be represented: int, long int;...

Update

Another relevant type deduction rule might be 14.8.2.1.2.

If P is not a reference type:

[...]

— If A is a cv-qualified type, the top level cv-qualifiers of A’s type are ignored for type deduction.

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.

The code provided by OP wouldn't even compile because it's illegal to bind a non-const reference to rvalue.

Broadcloth answered 13/8, 2012 at 9:36 Comment(13)
Wow, really? I didn't know that, thanks for letting me know... I guess I had a bad example in the question for illustrating my point. I just fixed it in the question. But the problem still persists even when I explicitly cast it to const int, so that's not the real issue, right?Karly
@Mehrdad, which "problem" exactly?Carrousel
@SingerOfTheFall: It's in the title. When I pass a const parameter to foo, such as in my (fixed) example, why doesn't T become inferred as the given const type?Karly
@Mehrdad: If you actually passed a const lvalue argument, like const int i = 42; foo(42); it will. The problem doesn't lie with const-ness, but with lvalue-/rvalueness.Phospholipide
@Xeo: Uh, then why doesn't it work with r-values?Karly
@Mehrdad - what makes you think, it's not passed as const?Selfexecuting
@KirilKirov: Because it doesn't even compile (see my example).Karly
@Mehrdad: Because the rules say so. int& also doesn't bind to an rvalue of type int, so why should T& bind to an rvalue of type T? That's just the kind of game template argument deduction plays.Phospholipide
@Xeo: "why should T& bind to an rvalue of type T?"... wait, but T doesn't even exist yet, so asking "why should T& bind to T" doesn't even make sense, since it assumes T exists as a real type. T has to be inferred first, so I'm asking why it isn't inferred as const int? If it were inferred as const int, then const int& could very well bind to const int, no problem.Karly
Andrey: Thanks for the reference to the standard. Do you happen to know why the standard explicitly ignores A's const modifier during type deduction? (Is it meant to protect against some error, or is it too time-consuming for the compiler to figure out, or something else?) I'm assuming the decision wasn't made arbitrarily, given that it's mentioned explicitly, even though it prevents otherwise-seemingly-valid code from compiling.Karly
Your comments are fine as far as they go, but they don't apply to his example. He's not instantiating with an integral literal, but with a cast expression. And only the last point of your second quote applies, since in his case, P is a reference type (with no top level const). The reason his code doesn't compile (or results in T = int in one broken compiler) is because the expression ((int const)5) is an rvalue of a non-class type, and rvalues of non-class type don't have cv-qualifiers (even when you explicitly say that they should).Fix
@Mehrdad: James Kanze just has given an excellent explanation. The relevant clause in the standard is 3.10/9: non-class rvalues always have cv-unqualified typesBroadcloth
@Andrey: Yup, I saw his answer, thanks. :)Karly
F
7

It does, if it's given a const type. Rvalues (prvalues in C++11) with non-class types, however, are never cv-qualified, even if you try to say they are: the expression ((const int)5) has type int. The reasoning here is that cv-qualifications only apply to objects, and temporaries of non-class types aren't objects, but pure values; cv-qualifications can't apply, because there's nothing to be const or volatile.

If you write:

int const i = 42;
foo( i );

, your template will instantiate with T = int const. (As you wrote it, the code shouldn't compile, because the deduced type is int, so the function takes an int&, which can't be initialized with an rvalue.)

Fix answered 13/8, 2012 at 10:5 Comment(6)
Just to clarify, what exactly is the "non-class type" here that you're talking about? int or int& or const int or const int&? (I'm not sure I know the meaning of the term well enough to understand your answer yet.)Karly
Since we're talking about adding cv-qualifiers to it, the type must be int. In the original code, at least, the type would have been int const (after the cast), except that rvalues of non-class type don't have cv-modifiers. (It's interesting to note that casting to int const& should work.)Fix
Whoa, so struct Foo { }; foo((const Foo)Foo()); works fine?! I never knew that! +1 it makes absolutely no sense why int is any different from an arbitrary struct but this seems to be the correct explanation, thanks..Karly
@Mehrdad History. It makes no sense, except that in C, rvalues are never cv-qualified, and C++ wants to behave identically (although in this case, I don't see how it could matter). But whether a class type is const or not affects function overload resolution: which function you call in something like foo().bar(), for example. So cv-qualifiers have to have an impact on class types. Anyhow, that's the rationale I was given.Fix
What exactly would the difference between a normal 42 and a const 42 be?Plant
@FredOverflow The type, since const is part of the C++ type system. (Presumably, if C++ had gone this route, the type of 42 would be int const, and there would be no literal with type just int.)Fix

© 2022 - 2024 — McMap. All rights reserved.