binding a lvalue to a rvalue reference under MSVS2010 - c++

#include<iostream>
template<class T>
struct Foo
{
T v_;
Foo(T&& v):v_(std::forward<T>(v))
{
std::cout << "building Foo..\n";
}
};
int main()
{
int v;
Foo<int> foo(v);
std::cin.ignore();
}
visual c++ 2010 output :
error C2664: 'Foo<T>::Foo(T &&)' : cannot convert parameter 1 from 'int' to 'int &&'
Is it normal that I can't bind a lvalue to a rvalue reference ?
EDIT:
same thing for a function :
void f(int && v)
{
}
int v;
f(v); //won't compile
I'm a little bit confused because I think std::forward is usefull to detect if a method is called with a lvalue or a rvalue reference.
But it seems that we can't bind any lvalue into rvalue reference... at least without template parameter but I don't understand it very well

It's normal that calling a move constructor requires an r-value, not an l-value, since an l-value could be named after the move constructor runs, and using a moved-from value would evoke unintended behavior.

Related

C++14 Template function forwarding reference deduced explicitly by pointer

Explain, please, what's wrong with this code?
An unusual behaviour is that f3 is working, when deduced implicitly, but is not, when is forcely specialized.
template<typename T>
void f1(T x) {}
template<typename T>
void f2(T& x) {}
template<typename T>
void f3(T&& x) {}
int main()
{
int x = 0;
f1(x); // ok
f2(x); // ok
f3(x); // ok
f1<int>(x); // ok
f2<int>(x); // ok
f3<int>(x); // error
}
VS2017. Compilier message:
error C2664: "void f3(T &&)": unable to convert argument 1 from "int" to "T &&"
I thought I'm doing exactly the same specifying int explicitly. And only difference that deduction in this case f3(x); was done by compiler and in this one f3<int>(x); by me.
I'm not 100% sure, please someone correct me if I'm wrong:
Because in case of f3(x) the deduced type is f3<int&>( int& && ).
There is an Errror becuase l-values and l-values references cannot be used to initialize r-value references. R-values references can only be initialized with r-values only.
You can use PRETTY_FUNCTION to get the Function being called along with the arguments that are deduced.
f1(a); // ok deduces to void f1(T) [T = A *]
f2(a); // ok deduces to void f2(T &) [T = A *]
f3(a); // ok deduces to void f3(T &&) [T = A *&]
f1<A*>(a); // ok . No Deduction as T already specified void f1(T) [T = A *]
f2<A*>(a); // ok . No Deduction as T already specified to void f2(T) [T = A *]
f3<A*>(a); // Errror becuase l-values and l-values references
// cannot be used to r-value references.
// R-values references can only be initialized with r-values only.

How do I call an rvalue member function from another rvalue member function? [duplicate]

I have trouble to implement following code
template <class T>
struct Foo
{
std::vector<T> vec;
std::vector<T> getVector() && {
// fill vector if empty
// and some other work
return std::move(vec);
}
std::vector<T> getVectorAndMore() &&
{
// do some more work
//return getVector(); // not compile
return std::move(*this).getVector(); // seems wrong to me
}
};
int main()
{
Foo<int> foo;
auto vec = std::move(foo).getVectorAndMore();
}
The problem is that I can't call getVector inside getVectorAndMore because this is not rvalue. To make the code compile, I had to cast this to rvalue.
Is any good way to implement such code?
with return getVector();
error message is
main.cpp:17:16: error: cannot initialize object parameter of type 'Foo<int>' with an expression of type 'Foo<int>'
return getVector(); // not compile
^~~~~~~~~
main.cpp:26:31: note: in instantiation of member function 'Foo<int>::getVectorAndMore' requested here
auto vec = std::move(foo).getVectorAndMore();
^
1 error generated.
Coliru
return getVector(); // not compile
This is equivalent to this:
return this->getVector(); // not compile
which wouldn't compile, because this is an lvalue, not an rvalue and getVector() can be invoked only on rvalue, hence the error.
Note that this is always an lvalue — even inside rvalue-ref member function!
return std::move(*this).getVector();
That is the correct way to invoke getVector().

C++ template specialization rvalue

I'm learning C++ and have a little problem with template specialization. I need to call Variable.Set() a lot so, I made the function take in references so it doesn't spend a lot of time copying the string. But then the problem I have is Variable.Set<int>(5); causes error because the parameter is an rvalue and I don't know the solution for this.
error C2664: 'void Variable::Set(int &)': cannot convert argument 1 from 'int' to 'int &'
void main()
{
Variable var;
var.Set<int>(5);
}
struct Variable
{
int integer;
float floating;
std::string string;
template<typename T> void Set(T& v);
template<> void Set<int> (int& v) { integer = v; }
template<> void Set<float> (float& v) { floating = v; }
template<> void Set<std::string> (std::string& v) { string = v; }
};
You need to change your parameters to constant references (const& as mentioned in Praetorian's comment)
From this link: http://www.codesynthesis.com/~boris/blog/2012/07/24/const-rvalue-references/
while a const lvalue reference can bind to an rvalue, a const
rvalue reference cannot bind to an lvalue

explicit call of templated overloaded operator

i have a class with a overladed operators.
class sout {
public:
template<typename T>
friend inline sout& operator&(sout&, T&);
friend inline sout& operator&(sout&, std::string&);
};
now if i use the templated operator& inside the the sting.operator& i get an error:
code:
sout& operator&(sout& s, std::string& str) {
uint16_t ts = static_cast<uint16_t>(str.size()); // this is ok
s & ts; // is also ok
s & static_cast<uint16_t>(str.size()); // but this is wrong
// ...
return s;
}
error:
Error:C2679: binary '&' : no operator found which takes a right-hand operand of type 'uint16_t' (or there is no acceptable conversion)
could be 'sout &operator &<uint16_t>(sout &,T &)'
with
[
T=uint16_t
]
or 'sout &operator &(sout &,std::string &)'
while trying to match the argument list '(sout, uint16_t)'
than i tried to use the explicite operator& template-type by:
operator&<uint16_t>(s, ts); // this also ig ok
but if i combine it, i again a error:
operator&<uint16_t>(s, static_cast<uint16_t>(str.size())
error:
'operator &' : cannot convert parameter 2 from 'uint16_t' to 'uint16_t &'
i also tried reinterpret_cast.
i know operator& is expecting a reference to uint16_t and the size() function is returning a size_t (int) not a reference. is it possible to do that in one line?
The problem is that the value returned by size() is a temporary, and temporaries are rvalues; however, your function accepts an lvalue reference. The following snippet clarifies the problem:
int foo() { return 42; }
void bar(int& i) { i++; } // Parameter is an lvalue reference to non-const
int main()
{
bar(foo()); // ERROR! Passing an rvalue to bar()
bar(1729); // ERROR! Passing an rvalue to bar()
int i = 42;
bar(i); // OK! Passing an lvalue to bar()
}
lvalue references cannot bind to rvalues, unless they are references to const.
template<typename T>
friend inline sout& operator&(sout&, T const&);
// ^^^^^
If your operator& is supposed to modify the right hand argument, so that the reference cannot be a reference to const, in C++11 you may use rvalue references (this will allow to bind to lvalues as well due to C++11's reference collapsing rules):
template<typename T>
friend inline sout& operator&(sout&, T&&);
// ^^^

C++0x rvalue reference template argument deduction

Given GMan's deliciously evil auto_cast utility function concocted here, I've been trying to figure out why it doesn't compile for me when I'm trying to auto_cast from an rvalue (on MSVC 10.0).
Here's the code that I'm using:
template <typename T>
class auto_cast_wrapper : boost::noncopyable
{
public:
template <typename R>
friend auto_cast_wrapper<R> auto_cast(R&& pX);
template <typename U>
operator U() const
{
return static_cast<U>( std::forward<T>(mX) );
}
private:
//error C2440: 'initializing': cannot convert from 'float' to 'float &&'
auto_cast_wrapper(T&& pX) : mX(pX) { }
T&& mX;
};
template <typename R>
auto_cast_wrapper<R> auto_cast(R&& pX)
{
return auto_cast_wrapper<R>( std::forward<R>(pX) );
}
int main()
{
int c = auto_cast( 5.0f ); // from an rvalue
}
To the best of my ability I've tried to follow the C++0x reference collapsing rules and the template argument deduction rules outlined here, and as far as I can tell the code given above should work.
Recall that in pre-0x C++, it is not allowed to take a reference to a reference: something like A& & causes a compile error. C++0x, by contrast, introduces the following reference collapsing rules:
A& & becomes A&
A& && becomes A&
A&& & becomes A&
A&& && becomes A&&
The second rule is a special template argument deduction rule for function templates that take an argument by rvalue reference to a template argument:
template<typename T>
void foo(T&&);
Here, the following rules apply:
When foo is called on an lvalue of type A, then T resolves to A& and hence, by the reference collapsing rules above, the argument type effectively becomes A&.
When foo is called on an rvalue of type A, then T resolves to A, and hence the argument type becomes A&&.
Now when I mouse over the call to auto_cast( 5.0f ), the tooltip correctly displays its return value as auto_cast_wrapper<float>. This meaning that the compiler has correctly followed rule 2:
When foo is called on an rvalue of type A, then T resolves to A.
So since we have an auto_cast_wrapper<float>, the constructor should instantiate to take a float&&. But the error message seems to imply that it instantiates to take a float by value.
Here's the full error message, showing again that T=float correctly yet the T&& parameter becomes T?
main.cpp(17): error C2440: 'initializing' : cannot convert from 'float' to 'float &&'
You cannot bind an lvalue to an rvalue reference
main.cpp(17) : while compiling class template member function 'auto_cast_wrapper<T>::auto_cast_wrapper(T &&)'
with
[
T=float
]
main.cpp(33) : see reference to class template instantiation 'auto_cast_wrapper<T>' being compiled
with
[
T=float
]
Any thoughts?
You forgot to std::forward the T&& argument to the auto_cast_wrapper constructor. This breaks the forwarding chain. The compiler now gives a warning but it seems to work fine.
template <typename T>
class auto_cast_wrapper
{
public:
template <typename R>
friend auto_cast_wrapper<R> auto_cast(R&& pX);
template <typename U>
operator U() const
{
return static_cast<U>( std::forward<T>(mX) );
}
private:
//error C2440: 'initializing': cannot convert from 'float' to 'float &&'
auto_cast_wrapper(T&& pX) : mX(std::forward<T>(pX)) { }
auto_cast_wrapper(const auto_cast_wrapper&);
auto_cast_wrapper& operator=(const auto_cast_wrapper&);
T&& mX;
};
template <typename R>
auto_cast_wrapper<R> auto_cast(R&& pX)
{
return auto_cast_wrapper<R>( std::forward<R>(pX) );
}
float func() {
return 5.0f;
}
int main()
{
int c = auto_cast( func() ); // from an rvalue
int cvar = auto_cast( 5.0f );
std::cout << c << "\n" << cvar << "\n";
std::cin.get();
}
Prints a pair of fives.
Sorry for posting untested code. :)
DeadMG is correct that the argument should be forwarded as well. I believe the warning is false and the MSVC has a bug. Consider from the call:
auto_cast(T()); // where T is some type
T() will live to the end of the full expression, which means the auto_cast function, the auto_cast_wrapper's constructor, and the user-defined conversion are all referencing a still valid object.
(Since the wrapper can't do anything but convert or destruct, it cannot outlive the value that was passed into auto_cast.)
I fix might be to make the member just a T. You'll be making a copy/move instead of casting the original object directly, though. But maybe with compiler optimization it goes away.
And no, the forwarding is not superfluous. It maintains the value category of what we're automatically converting:
struct foo
{
foo(int&) { /* lvalue */ }
foo(int&&) { /* rvalue */ }
};
int x = 5;
foo f = auto_cast(x); // lvalue
foo g = auto_cast(7); // rvalue
And if I'm not mistaken the conversion operator shouldn't be (certainly doesn't need to be) marked const.
The reason it doesn't compile is the same reason for why this doesn't compile:
float rvalue() { return 5.0f }
float&& a = rvalue();
float&& b = a; // error C2440: 'initializing' : cannot convert from 'float' to 'float &&'
As a is itself an lvalue it cannot be bound to b. In the auto_cast_wrapper constructor we should have used std::forward<T> on the argument again to fix this. Note that we can just use std::move(a) in the specific example above, but this wouldn't cover generic code that should work with lvalues too. So the auto_cast_wrapper constructor now becomes:
template <typename T>
class auto_cast_wrapper : boost::noncopyable
{
public:
...
private:
auto_cast_wrapper(T&& pX) : mX( std::forward<T>(pX) ) { }
T&& mX;
};
Unfortunately it seems that this now exhibits undefined behaviour. I get the following warning:
warning C4413: 'auto_cast_wrapper::mX' : reference member is initialized to a temporary that doesn't persist after the constructor exits
It appears that the literal goes out of scope before the conversion operator can be fired. Though this might be just a compiler bug with MSVC 10.0. From GMan's answer, the lifetime of a temporary should live until the end of the full expression.