Converting arrays into vectors inside function argument - c++

Let's imagine that there is some data stored into an array that needs to go through a function that accepts vector. In this situation, clearly the array data needs to be converted into the respective vector type. One general approach would be
std::vector<int> vec(arr, arr+n);
function(vec);
where arr is the mentioned array variable. I know that we added just one line, but its looks somehow as an unnecessary code pollution. So I tried this
function(std::vector<int>(arr, arr+n))
what worked. Bellow there is a detailed code this.
#include <vector>
#include <iostream>
void print(std::vector<int> vec){
for(unsigned int i=0; i!=vec.size(); ++i){
std::cout << vec[i] << std::endl;
}
}
int main(){
int a[] = {2,1,4,5,6};
print(std::vector<int>(a,a+5));
}
From this, my first question is: This approach is ok, or it has some undesired behavior?
After that, I decided to change the function argument to accept a vector reference like
void print(std::vector<int> &vec){
for(unsigned int i=0; i!=vec.size(); ++i){
std::cout << vec[i] << std::endl;
}
}
what did not work. Here is the error that I got
test.cpp: In function ‘int main()’:
test.cpp:13:34: error: invalid initialization of non-const reference of type ‘std::vector<int>&’ from an rvalue of type ‘std::vector<int>’
print(std::vector<int>(a,a+5));
^
test.cpp:4:6: error: in passing argument 1 of ‘void print(std::vector<int>&)’
void print(std::vector<int> &vec){
Here is the second question: Why, when the function argument as chanced to a vector reference this approach did not work. There is someway to get around this compiler error keeping the approach of creating the vector object in the argument function or not?

The problem is binding a rvalue (std::vector<int>(a,a+5) in the function call) to a lvalue reference (std::vector<int> &vec in the parameter list of the function). A rvalue can bind to a const lvalue reference, so as long as the parameter will not be changed the simplest solution is to write
void print(const std::vector<int> &vec)
which by the way saves you one copy operation on the vector. Or you could write a function overload binding explicitly to rvalues by having a rvalue reference parameter.
void print(std::vector<int>&& vec)
But you have to be aware of the fact, that this overload will only bind to rvalues. So you will have to maintain two functions, one for lvalues and one for rvalues.
For further reference on lvalues and rvalues, see for example Understanding lvalues and rvalues in C and C++ or ask your favourite search engine ;-).

In this line print(std::vector(a, a+5)), the compiler creates a temporary object which is a rvalue reference. Here we are trying to pass a reference value to a function which accepts non const lvalue reference, hence the compiler error. Instead if you declare print() method to accept a rvalue reference then you can get rid of the compilation error. Please see the code snippet below
#include <vector>
#include <iostream>
void print(std::vector<int> && vec) {
for(unsigned int i=0; i != vec.size(); ++i) {
std::cout << vec[i] << std::endl;
}
}
int main() {
int a[] = {2,1,4,5,6};
print(std::vector<int>(a,a+5));
}
The more on lvalue, rvalue reference, please refer http://en.cppreference.com/w/cpp/language/reference

Related

About the choice of the declations of `std::vector::push_back`

There two declarations for std::vector::push_back.I understand rvalue and lvalue to some degree. As far as i know, almost all types(T&、T&&、T) could be converted to const T&, so which one does the compiler choose when different types of object passed to std::vector::push?
I am a novice in C++.Though i thought over and over, i still could not get the idea.It would be better if you could give me some simple examples to make it clear.I would be greateful to have some help with this question.
As per the documatation(http://www.cplusplus.com/reference/vector/vector/push_back/), which says that:
void push_back (const value_type& val);
void push_back (value_type&& val);
Adds a new element at the end of the vector, after its current
last element. The content of val is copied (or moved) to the new
element.
Lvalues cannot be bind to rvalue referneces, which implies, that when you invoke std::vector<T>::push_back with an lvalue argument, the only viable overload is that with const T& parameter.
Rvalues can be bind to both rvalue references and const lvalue references. Therefore, both overloads are applicable. But according to the C++ overload rules, the overload with rvalue reference parameter T&& will be selected.
You can easily try this by yourself:
void f(const int&) { std::cout << "L"; }
void f(int&&) { std::cout << "R"; }
int main()
{
int i = 0;
f(i); // prints "L"
f(0); // prints "R"
}

decltype, universal references and forward for containers in C++

I am reading about decltype and rvalue references in effective modern C++ by Scott Meyers book. I have following code
template <typename container, typename index>
decltype(auto) authAndAccess(container&& c, index i) {
std::cout << "auth and Access c type: " << typeid(c[i]).name() << std::endl;
std::cout << "auth and Access c type expecting reference: " << typeid(std::forward<container>(c)[i]).name() << std::endl;
return std::forward<container>(c)[i];
}
deque<int> makeStringDeque() {
deque<int> dqContainer = { 1,2,3,4,5 };
return dqContainer;
}
now in main function I have following
deque<int> dqContainer = { 1,2,3,4,5 };
std::cout << "Value returned by container: " << authAndAccess(dqContainer, 4) << std::endl;
authAndAccess(deque<int>{1, 2, 3, 4, 5}, 4) = 10;
std::cout << "Value returned by container and 5th element after copying: " << dqContainer[4] << endl;
My question is authAndAccess function takes rvalue argument so container is temporary and return is object is temporary reference element. But why output is shown as int for typeid of forwared for which I am expecting int &. I do understand name function of typeid is not accurate, but why it is not crashing as we are returning temporary element reference.
My question is authAndAccess function takes rvalue argument so container is temporary and return is object is temporary reference element.
authAndAccess takes what Scott called a Universal Reference, which is now called a forwarding reference, so it can accept lvalue and rvalue arguments. When you pass it a lvalue, you get a lvalue reference and when you pass it an rvalue you get a rvalue reference. std::forward<container> does the same thing. If container is a lvalue, you get a lvalue and for rvalues you get a rvalue.
That means authAndAccess(dqContainer, 4) is fine since you are returning a reference to an object in dqContainer which still exists. In authAndAccess(makeStringDeque(), 4) you would think you have undefined behavior since makeStringDeque() is a temporary and you are returning a reference to it but since you don't keep it, there is no UB since the reference will be valid until the end of the full expression.
But why output is shown as int for typeid of forwared for which I am expecting int &.
typeid won't tell you if you have a reference. You can see that in this minimal example
int main(int argc, char* argv[])
{
int a = 5;
int & b = a;
std::cout << typeid(b).name();
}
which outputs i. If you wan to get the type you can use a declared but not defined class template and give the type to it and you'll get an error message telling you what the actual type is. If we change the above code to
template<typename T>
struct type;
int main(int argc, char* argv[])
{
int a = 5;
int & b = a;
type<decltype(b)>{};
}
we will get an error like
main.cpp:14:5: error: implicit instantiation of undefined template 'type<int &>'
type<decltype(b)>{};
and as you can see it deduces the type as int &. If we do that in your code it also gives int & since that is the return type of c[i].

error: invalid initialization of non-const reference of type 'std::function<void()>&' from an rvalue of type 'main()::<lambda()>'|

EDIT: Sorry, I asked this question without a thro understanding of references...
I seem to be getting this error when I run this code...
error: invalid initialization of non-const reference of type 'std::function&' from an rvalue of type 'main()::'
#include <bits/stdc++.h>
using namespace std ;
void printfunction(bool a, function <void()> &b)
{
if (a == true)
{
b() ;
}
}
int main()
{
int value = 45 ;
printfunction(true, [value](){cout << "The value is : " << value ;}) ;
}
But, the error disappears when I add a const before function... like this :
void printfunction(bool a,const function <void()> &b)
The thing is I would like to change the function in the function reference if needed...
Is there any other way to do this? Please let me know if it does indeed exist.
Bye,
Samuel
In printfunction call, lambda expression [value]() {...} argument must be converted to a temporary function<void()> object first.
A reference to non-const function<void()>& only binds to l-values, not temporaries (r-values).
A reference to const, on the other hand, can be bound to temporaries. Which is what you observe.
If you want to modify the std::function, then you'll need to pass a modifiable (lvalue) parameter:
int main()
{
int value = 45;
std::function f = [value](){ std::cout << "The value is : " << value ;};
printfunction(true, f);
}
What you were trying to do isn't much different from writing a function that takes a mutable reference to int (e.g. void foo(int& x)) and then complaining that you can't call foo(5). (The small difference is that the the lambda-expression is converted to a temporary std::function - but that still can't be bound to a non-const reference).
An alternative would be to change printfunction to take its argument by value rather than by reference, so that it has its own copy which it may modify. You'll have to consider the needs of the caller to decide whether that's more appropriate.

Is the hard coded value in function argument a const reference?

Why does the following program fail to compile:
#include<iostream>
using namespace std;
int fun(int &x)
{
return x;
}
int main()
{
cout << fun(10);
return 0;
}
It gives the following compilation error:
invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
To make it compile successfully , I have 2 options:
1. we have to use "int fun(const int &x)" instead of "int fun(int &x)"
2. use "int i=10;cout << fun(i);" instead of "cout << func (10)"
So, it seems like , if we pass a hard coded value to a function , it will be treated like "const reference".
Am I right here? or is there any other reason that above program doesn't compile?
This doesn't compile because non-const lvalue references cannot bind to rvalues.
Think about it this way: if x in fun is a non-const lvalue reference, we should be able to modify it. However, we have passed in the integer literal 10. What should it mean to modify an integer literal? That doesn't make sense, so you can't.
To fix this, you should take your argument in by reference-to-const (assuming you don't plan on modifying it in fun):
int fun(const int &x)

invalid initialization of non-const reference of type 'int&', what the reason?

I have the given code, which gets an error:
error: invalid initialization of non-const reference of type 'int&'
from an rvalue of type 'int' const int b = f(a++);
^
int f(int& a)
{
return a;
}
int main() {
// your code goes here
int a = 5;
int b = f(a++);
std::cout << b << std::endl;
return 0;
}
What the cause of this error ?
You can't bind a temporary to a non-const reference.
Post-increment (a++) increments a and returns a temporary with a's old value.
Why are you passing by non-const reference? - it doesn't look like you're changing the parameter inside the function, just just pass by value or const reference.
If you were changing the parameter, what would you expect the behavior to be, considering a++ already changes it? Would the change be intuitive? Legal?
The postfix increment operator on an int returns a temporary value. A temporary value cannot bind to a non-const lvalue reference, because modifying that temporary doesn't make sense. You are trying to bind the temporary to an int&, which is giving an error.
To fix this, either use the pre-increment operator (++a), or take your argument by value (it's better to pass builtin types as value rather than const T&):
int f(int a)
{
return a;
}
This function:
int f(int& a)
accepts non-const reference. Such references must always point to a valid objects, residing at certain memory locations (*).
Post incrementation works as follows:
- save current value as `r`
- increment original variable
- return `r`
That's because result of post-incrementation is a temporary, yielding value from before incrementation. Such temporary must be passed either as value or const reference:
int f(int a) //This will work
int f(const int& a) //And this
(*) In fact, older compilers allowed for such constrcuts. For example, this code will compile under VC6:
struct T {};
void f(T& t)
{
}
int main()
{
f(T());
}
However, such behaviour is not standard-compliant.