views:

139

answers:

4

hello.

Can you please explain me the difference between mechanism of the following:

int function();

template<class T>
void function2(T&);

void main() {
    function2(function()); // compiler error, instantiated as int &

    const int& v = function();
    function2(v); // okay, instantiated as const int&
}

is my reasoning correct with respect to instantiation? why is not first instantiated as const T&?

Thank you

A: 

In this line

function2(function()); 

after function2 returns, the argument that passes to it might have its value change, but since function() returns and it's just assigned to a temporary variable, but what would happen to this temporary variable after it goes out of scope is the problem, that's why the compiler complaints.

Khnle
A: 

To compile the first call, it is necessary to define function2 with T&& parameter - this is rvalue, reference to temporary object. In the second call, v is lvalue reference, it is OK. If your compiler doesn't support rvalue references, the first call may be compiled only with T parameter, without reference.

Alex Farber
+4  A: 

Because function returns a non-const value. Only objects can be const, because they store some state that could be modified if it weren't const. What you return there is not an object, but a pure value. Conceptually, they are not modifiable (like enumeration constants, for example), but they are not const qualified (like, again, enumeration constants).

Johannes Schaub - litb
@aca To be more precise, [non-class rvalues always have cv-unqualified types](http://stackoverflow.com/questions/2169932/non-class-rvalues-always-have-cv-unqualified-types) ;-) For class-types, there is a distinction between modifiable rvalues and const rvalues, so in general, the `const` is *not* superfluous! You can call non-const methods on modifiable rvalues and thus change the underlying objects. For example, `std::string("hello ").append("world!")`.
FredOverflow
@FredOverflow yep good point. Notice that array rvalues are qualified likewise (the Standard says they are not, but they are nontheless - you cannot write `struct A { const int a[1]; }; .. A().a[0] = 0;` in most compilers (except in comeau, where you can) - but if you remove the `const`, you can (there have been questions on usenet and elsewhere about this - no solution has been found yet). Also notice that any non-class/non-array rvalue is not an object. Class-type/array-type rvalues are objects, thus const makes sense for them (see foot-note on 4.1/1 in the Standard).
Johannes Schaub - litb
@FredOverflow i wonder what @aca commented that you replied on? Did he remove his comment?
Johannes Schaub - litb
Yes. I can't remember the exact content anymore, but it was something about rvalues being always implicitly constant or something, and he did not agree with your statement "Only objects can be const" IIRC.
FredOverflow
@FredOverflow ahh thanks :)
Johannes Schaub - litb
Anyway, it was obviously nonsense, otherwise he would not have deleted the comment. Which is fine, I do that too from time to time :)
FredOverflow
@FredOverflow, yeah. But too bad he can't retract his downvote anymore :( http://meta.stackoverflow.com/questions/30470/mistaken-downvote-cannot-be-undone-after-matter-is-being-clarified-by-the-answere
Johannes Schaub - litb
Not even if you edit your answer?
FredOverflow
@FredOverflow i find it silly to do that just to get my points back back. I consider it a bug in the system :)
Johannes Schaub - litb
+2  A: 

I think that you might be confused between rvalues and the const qualifier. function returns a non-const rvalue temporary of type int, so the compiler deduces T to be int, as it should. As you point out, you can bind a temporary to a const ref (c++03 12.2/5), but the compiler will not add cv qualifiers to make a function call well formed. Since you can't control the template function, there are two ways around this (in addition to the solution you posted).

(1) Explicit template parameters: function2<const int>(function())

(2) cv qualify return: const int function();

Both of these solutions are well formed. (1) seems the better solution, IMHO, since (2) is unconventional and silly.

Edit: Actually, the deduced type can be more cv-qualified than the argument for a ref template argument, but only if type deduction would otherwise fail (c++03 14.8.2.1/3). In this case, type deduction doesn't fail, but results in a malformed function call (SFINAE does not apply, because the template function specialization itself is not malformed).

If the intent of the template author was to not modify the argument, it should be declared as a const reference argument, so this may be a bug in the template library, or it may modify the argument, in which case what you are doing will fail where the function attempts to modify the argument.

Edit: As FredOverflow points out, non-class rvalues are always cv unqualified by the standard 3.10/9. So (2), which works under gcc 4.3, is actually a compiler bug (gcc <4.5, according to FredOverflow).

academicRobot
There is no difference whatsoever between `int function()` and `const int function()`, because [non-class rvalues always have cv-unqualified types](http://stackoverflow.com/questions/2169932/non-class-rvalues-always-have-cv-unqualified-types).
FredOverflow
@FredOverflow. Ideally no, but its different to gcc ;)
academicRobot
@aca Hm? The issue mentioned in the linked thread has been fixed in the latest g++ compiler.
FredOverflow
academicRobot
@aca 4.5.0 complains with `invalid initialization of non-const reference of type 'int-)
FredOverflow
Johannes Schaub - litb
@Johannes: Hmm, good to known, thanks.
FredOverflow