tags:

views:

112

answers:

2

If you have this function

template<typename T> f(T&);

And then try to call it with, let's say an rvalue like

f(1);

Why isn't T just be deduced to be const int, making the argument a const int& and thus bindable to an rvalue?

+1  A: 
Zack
Yes, I know about the overloading. I wanted to know why it's even necessary. How would it be inconsistent?
DeadMG
@DeadMG: `1` has type `int`. If you declared an `int i = 1`, then it would choose the non-const approach, because `i` isn't const. Therefore, for consistency, it does so here too, except that for an rvalue this is an error.
Matthieu M.
@Matthieu: 1 is an int rvalue. i is an int lvalue. Since the language insists on treating them differently, then they are different things. Therefore, it's not inconsistent. Infact, it's inconsistent to have a bunch of rules specially for rvalues, and then try to treat them the same here.
DeadMG
@DeadMG: I agree that the standard is strange, I personally think that `1` should be of type `int const` because hey, I can't change it! However it's not how the standard said it was, and therefore it isn't. As for the interdiction to take `rvalue` by reference I never could like it, it doesn't make sense from the C++ philosophy point of view which happily let's you shoot yourself if you wish to prevent this when it can be so useful (for forwarding, for "sink"-like behavior etc), after all, why couldn't I modify a temporary and be happy with it ? But the standard is law, and thus IS consistent
Matthieu M.
+8  A: 

This is mentioned as a potential solution in the document I linked in the recent C++0x forwarding question.

It would work fairly well, but it breaks existing code. Consider (straight from the document):

template<class A1> void f(A1 & a1)
{
    std::cout << 1 << std::endl;
}

void f(long const &)
{
    std::cout << 2 << std::endl;
}

int main()
{
    f(5);              // prints 2 under the current rules, 1 after the change
    int const n(5);
    f(n);              // 1 in both cases
}

Or

// helper function in a header

template<class T> void something(T & t) // #1
{
    t.something();
}

// source

#include <vector>

void something(bool) // #2
{
}

int main()
{
    std::vector<bool> v(5);

    // resolves to #2 under the current rules, #1 after the change
    something(v[0]);
}

This also fails to forward the value category (lvalue or rvalue), which isn't much of a problem in C++03. But since this fix could only be done during C++0x, we'd effectively shutting ourselves out from rvalue references when forwarding (a bad thing). We should strive for a better solution.

GMan