I have some Qt code that I downloaded from my svn repo. It's a while since I worked on it but I am sure it used to compile.
I have a new version of Qt and compiler (to what I had in the last time). My current compiler is: mingw 4.9.2 32-bit.
So here is my problem code:
QByteArray dataBlock = audioTestFile.read(PACKET_SIZE_TO_ENCODE);
// This line is the issue
uint8Vect_t testVect = encodeData(uint8Vect_t(dataBlock.begin(), dataBlock.end()));
Where:
typedef std::vector<uint8_t> uint8Vect_t;
and
uint8Vect_t encodeData(uint8Vect_t &dataBuff);
So you can see here that I have a function encodeData() which takes a parameter uint8Vect_t &
(pass by ref). I am passing a temporary variable (an rvalue I think) created using the std::vector constructor (one of which takes two iterators) from the QByteArray dataBlock
iterators (which I have tested works).
However, I get the error:
../audioTest/txaudiostream.cpp: In member function 'void CTxAudioStream::playFile()': ../audioTest/txaudiostream.cpp:212:94: error: no matching function for call to 'CTxAudioStream::encodeData(uint8Vect_t)' uint8Vect_t testVect = encodeData(uint8Vect_t(dataBlock.begin(), dataBlock.end())); ^ ../audioTest/txaudiostream.cpp:212:94: note: candidate is: ../audioTest/txaudiostream.cpp:36:13: note: uint8Vect_t CTxAudioStream::encodeData(uint8Vect_t&) uint8Vect_t CTxAudioStream::encodeData(uint8Vect_t &dataBuff) ^ ../audioTest/txaudiostream.cpp:36:13: note: no known conversion for argument 1 from 'uint8Vect_t {aka std::vector}' to 'uint8Vect_t& {aka std::vector&}'
Basically it's saying that I cannot convert from uint8Vect_t to uint8Vect_t&. But if I pass a variable of type uint8Vect_t into the function (rather then the return value of the contructor / temp variable) then this works ok.
I thought in c++11 you can pass rvalues.. but I am obviously missing something here. Can anyone explain:
Your issue is
uint8Vect_t encodeData(uint8Vect_t &dataBuff);
Here you are taking a reference to a uint8Vect_t
. That works well with normal variables but uint8Vect_t(dataBlock.begin(), dataBlock.end())
is a temporary object and cannot be bound to lvalue reference.
If encodeData()
does not change dataBuff
then the simplest solution is to take a const &
which can bind to a temproary.
uint8Vect_t encodeData(const uint8Vect_t &dataBuff);
If you have to change the contents of dataBuff
then you would have to write another version of encodeData()
that takes an rvalue reference
uint8Vect_t encodeData(uint8Vect_t &&dataBuff);
This will allow the function to bind to the temporary vector and you can work on it in the function as you would a normal vector.
I believe the reason you are seeing this is that your old compiler was a version of Microsoft Visual Studio. MSVS has a non standard extension that is on by default that allows temporary objects to bind to a lvalue reference. You can read more about it at: Non-const reference bound to temporary, Visual Studio bug?
Adding this to show you how you could change encodeData()
to take an rvalue reference without having to write a new function.
#include <iostream>
#include <vector>
std::vector<int> modify(std::vector<int>& foo)
{
for (auto & e : foo)
e *= 2;
return foo;
}
std::vector<int> modify(std::vector<int>&& foo)
{
return modify(foo);
}
int main()
{
std::vector<int> foo = modify({ 1,2,3,4,5 });
for (const auto & e : foo)
std::cout << e << " ";
}
Live Example
In the above example modify({ 1,2,3,4,5 })
calls modify(std::vector<int>&& foo)
and then in the function foo
is an lvaue. We then return the result of passing the "new" lvalue to modify(std::vector<int>& foo)
which then returns a modified vector.
When you use
encodeData(uint8Vect_t(dataBlock.begin(), dataBlock.end()))
the vector you pass into the function is a temporary object, and references can't bind to temporary objects.
The simple solution, if the function doesn't modify the argument, is to make it a reference to a constant object:
uint8Vect_t encodeData(uint8Vect_t const& dataBuff);
References to constant objects can bind to temporary objects.
What do you want to do with/to the object you are passing in?
When you take it as uint8Vect_t &dataBuff
that should mean you want to make lasting modifications to it, which makes no sense if it is a temporary.
When you take it as uint8Vect_t const&dataBuff
that should mean you want to copy from it and not modify it, which is probably what you want.
When you take it as uint8Vect_t dataBuff
that should mean you need your own local temporary copy of it, to use as you wish and then throw away, and that should be important enough to be worth the cost of copying.
When you take it as uint8Vect_t &&dataBuff
that should mean you want to make non lasting modifications (such as content stealing) from a temporary object that the caller is effectively promising to throw away after you are done with it.
That last choice is the one new in C++11 for passing rvalues.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With