Re: Overloading on rvalue and lvalue references
On 11 Sep., 20:59, Paul Bibbings wrote:
I am just starting to come to grips with rvalue references and how
they may be applied in several of the expected 'conventional' uses.
However, in some cases I find I have doubts based on an uncertainty
as to how well my compiler (gcc-4.3.2, Cygwin) actually implements
the current C++0x proposals for rvalue refs
It doesn't, actually. The following code still compiles with GCC 4.3
and GCC 4.4 in C++0x-mode but is NOT allowed anymore for safety
reasons
int main() {
int i = 42;
int&& r = i; // rv-ref to lvalue, ill-formed in C++0x
}
See N2812 for an introduction and N2844 for a detailed wording.
<code>
#include <iostream>
void foo(int&) { std::cout << "foo(int&)\n"; }
void foo(int&&) { std::cout << "foo(int&&)\n"; }
template<typename T>
void bar(T&) { std::cout << "bar(T&)\n"; }
template<typename T>
void bar(T&&) { std::cout << "bar(T&&)\n"; }
int main()
{
int i = 0;
foo(0); // #1
foo(i); // #2
bar(0); // #3
//bar(i); // #4 Error: ambiguous
return 0;
}
</code>
Yes. This is expected, regardless of the slight change of rules. But
you typically use lvalue-references-to-const for an "optimized pass-by-
value-style interface" (pass-by-value in the sense that the argument
is logically not modified, see vector<>::push_back for example).
[...]
If my understanding is correct, the call bar(0) (#3, rvalue) is
straightforward enough since the rvalue cannot bind to an lvalue
reference, and so
void bar<int>(int&&)
is instantiated, and used.
For the attempted call bar(i) (#4, lvalue), however, it seems
there will exist the two instantiations:
- void bar<int>(int& &); and
- void bar<int&>(int& &&)
where these become, after applying the reference collapsing rules:
- void bar<int>(int&); and
- void bar<int&>(int&)
and so disambiguation is not possible, hence the error (gcc-4.3.2).
Correct. If you write T&& and T will be deduced it's a "catch
everything" that is necessary for perfect forwarding. Nevertheless,
you can "apply SFINAE" to disable lvalues if you like:
#include <type_traits>
#define REQUIRES(...) ,class=typename \
std::enable_if<( __VA_ARGS__ )>::type
[...]
template<typename T
REQUIRES( ! std::is_reference<T>::value )
>
void bar(T&&) { std::cout << "bar(T&&)\n"; }
(I can't take credit for the nice REQUIRES macro but I don't know who
came up with the idea.)
Cheers,
SG
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]