Range based for loop through non-const literal c++ - c++

Compiler context: I am compiling with GDB v8.3 Ubuntu with options g++ -Im -O2 -std=c++0x.
Very frequently I need to complete some loop for two or three objects so I use wrap the expression in a range based for loop with a containing litteral.
In Python3 this would look like:
a = [1,2,3]
b = [4,5,6]
for v in (a,b):
func(v)
In c++ this obviously isn't so simple. As far as I am aware, using {a,b} creates some type of initializer list, therefor casting does not properly work. In my attempts I come to something of this sort, but do no understand how I would properly pass by reference and also have it be mutable, as my compiler complains this is neccessarily const.
vector<int> a {1,2,3};
vector<int> b {4,5,6};
for(auto& v: {a,b}) // error non-const
func(v);

Based on your python program, it appears that you want to iterate through all the vectors, but with a mutable reference to each vector. You can do this by using pointers:
for(auto *v: {&a, &b}) // iterate over pointers to the vectors
func(*v); // dereference the pointers to get mutable
// references to the vectors
Here's a demo.

int x,y;
for(int& i:{std::ref(x),std::ref(y)}){
i=7;
}
auto& won't work, and you do have to repeat std::ref for each element.
Another trick is:
auto action=[&](auto&foo){
// code
};
action(v1);
action(v2);
You can write:
void foreach_arg(auto&&f, auto&&...args){
((void)f(decltype(args)(args)),...);
}
or pre-c++20 versions in more characters, then:
auto action=[&](auto&foo){
// code
};
foreach_arg(action, v1, v2);
If you want the arguments mentioned first, you can do:
auto foreacher(auto&&...args){
return [&](auto&&f){
((void)f(decltype(args)(args)),...);
};
}
and get:
foreacher(v1,v2)([&](auto&v){
// loop body
});
apologies for any typos. Just writing insomnia-code, untested as yet.
decltype thing is a short std::forward equivalent in this case (with auto&& args; with some other declarations it doesn't work).
auto arguments to functions are a c++20 thing.
Then,... is comma-fold execute, a c++17 thing.
auto arguments to lambdas are a c++14 thing.
All can be replaced with c++11 constructs (in this case) at the cost of a lot more verbosity.

Related

Is it possible / advisable to return a range?

I'm using the ranges library to help filer data in my classes, like this:
class MyClass
{
public:
MyClass(std::vector<int> v) : vec(v) {}
std::vector<int> getEvens() const
{
auto evens = vec | ranges::views::filter([](int i) { return ! (i % 2); });
return std::vector<int>(evens.begin(), evens.end());
}
private:
std::vector<int> vec;
};
In this case, a new vector is constructed in the getEvents() function. To save on this overhead, I'm wondering if it is possible / advisable to return the range directly from the function?
class MyClass
{
public:
using RangeReturnType = ???;
MyClass(std::vector<int> v) : vec(v) {}
RangeReturnType getEvens() const
{
auto evens = vec | ranges::views::filter([](int i) { return ! (i % 2); });
// ...
return evens;
}
private:
std::vector<int> vec;
};
If it is possible, are there any lifetime considerations that I need to take into account?
I am also interested to know if it is possible / advisable to pass a range in as an argument, or to store it as a member variable. Or is the ranges library more intended for use within the scope of a single function?
This was asked in op's comment section, but I think I will respond it in the answer section:
The Ranges library seems promising, but I'm a little apprehensive about this returning auto.
Remember that even with the addition of auto, C++ is a strongly typed language. In your case, since you are returning evens, then the return type will be the same type of evens. (technically it will be the value type of evens, but evens was a value type anyways)
In fact, you probably really don't want to type out the return type manually: std::ranges::filter_view<std::ranges::ref_view<const std::vector<int>>, MyClass::getEvens() const::<decltype([](int i) {return ! (i % 2);})>> (141 characters)
As mentioned by #Caleth in the comment, in fact, this wouldn't work either as evens was a lambda defined inside the function, and the type of two different lambdas will be different even if they were basically the same, so there's literally no way of getting the full return type here.
While there might be debates on whether to use auto or not in different cases, but I believe most people would just use auto here. Plus your evens was declared with auto too, typing the type out would just make it less readable here.
So what are my options if I want to access a subset (for instance even numbers)? Are there any other approaches I should be considering, with or without the Ranges library?
Depends on how you would access the returned data and the type of the data, you might consider returning std::vector<T*>.
views are really supposed to be viewed from start to end. While you could use views::drop and views::take to limit to a single element, it doesn't provide a subscript operator (yet).
There will also be computational differences. vector need to be computed beforehand, where views are computed while iterating. So when you do:
for(auto i : myObject.getEven())
{
std::cout << i;
}
Under the hood, it is basically doing:
for(auto i : myObject.vec)
{
if(!(i % 2)) std::cout << i;
}
Depends on the amount of data, and the complexity of computations, views might be a lot faster, or about the same as the vector method. Plus you can easily apply multiple filters on the same range without iterating through the data multiple times.
In the end, you can always store the view in a vector:
std::vector<int> vec2(evens.begin(), evens.end());
So my suggestions is, if you have the ranges library, then you should use it.
If not, then vector<T>, vector<T*>, vector<index> depending on the size and copiability of T.
There's no restrictions on the usage of components of the STL in the standard. Of course, there are best practices (eg, string_view instead of string const &).
In this case, I can foresee no problems with handling the view return type directly. That said, the best practices are yet to be decided on since the standard is so new and no compiler has a complete implementation yet.
You're fine to go with the following, in my opinion:
class MyClass
{
public:
MyClass(std::vector<int> v) : vec(std::move(v)) {}
auto getEvens() const
{
return vec | ranges::views::filter([](int i) { return ! (i % 2); });
}
private:
std::vector<int> vec;
};
As you can see here, a range is just something on which you can call begin and end. Nothing more than that.
For instance, you can use the result of begin(range), which is an iterator, to traverse the range, using the ++ operator to advance it.
In general, looking back at the concept I linked above, you can use a range whenever the conext code only requires to be able to call begin and end on it.
Whether this is advisable or enough depends on what you need to do with it. Clearly, if your intention is to pass evens to a function which expects a std::vector (for instance it's a function you cannot change, and it calls .push_back on the entity we are talking about), you clearly have to make a std::vector out of filter's output, which I'd do via
auto evens = vec | ranges::views::filter(whatever) | ranges::to_vector;
but if all the function which you pass evens to does is to loop on it, then
return vec | ranges::views::filter(whatever);
is just fine.
As regards life time considerations, a view is to a range of values what a pointer is to the pointed-to entity: if the latter is destroied, the former will be dangling, and making improper use of it will be undefined behavior. This is an erroneous program:
#include <iostream>
#include <range/v3/view/filter.hpp>
#include <string>
using namespace ranges;
using namespace ranges::views;
auto f() {
// a local vector here
std::vector<std::string> vec{"zero","one","two","three","four","five"};
// return a view on the local vecotor
return vec | filter([](auto){ return true; });
} // vec is gone ---> the view returned is dangling
int main()
{
// the following throws std::bad_alloc for me
for (auto i : f()) {
std::cout << i << std::endl;
}
}
You can use ranges::any_view as a type erasure mechanism for any range or combination of ranges.
ranges::any_view<int> getEvens() const
{
return vec | ranges::views::filter([](int i) { return ! (i % 2); });
}
I cannot see any equivalent of this in the STL ranges library; please edit the answer if you can.
EDIT: The problem with ranges::any_view is that it is very slow and inefficient. See https://github.com/ericniebler/range-v3/issues/714.
It is desirable to declare a function returning a range in a header and define it in a cpp file
for compilation firewalls (compilation speed)
stop the language server from going crazy
for better factoring of the code
However, there are complications that make it not advisable:
How to get type of a view?
If defining it in a header is fine, use auto
If performance is not a issue, I would recommend ranges::any_view
Otherwise I'd say it is not advisable.

Inserters in C++ confusion

So I dont understand how to use inserters in this situation. I know what are inserters, I know about std::front_inserter and std::back_inserter and std::inserter but I am confused about this problem which I will present now.
I need to make function, which will transform elemets of vector and put them in deque(or vector nevermind, its "generic" function anyway).
That function has 5 parameters, which one of them is another function(which can have only one parameter, it is not specified what type(i mean it can be reference,iterator,pointer...... whatever)).
If my vector is:
std::vector<int> v={1,2,3,4,5};
I need to make some modification, with lambda function, which will make my deque have elements like this:
25 16 9 4 1
So you see that first element of deque is last element of vector ^2 (you can see what I want to do).
So my question is:
How can the problem be done using inserters? I mean should I somehow put inserter in lambda fucntion? Maybe lambda should be like this:
[](int x) {
x=x*x;
std::front_inserter(q);
}
I was thinking about this but then I dont understand how will this lambda work when I send it as parameter of this "big" function? How it will know what is q inside big function?
I hope you understand what I want to do.
Here is example.
So I have to make some function, and this is prototype(lets say it is void):
typename<template Type1, template Type2>
void Fun(Type1 p1,Type1 p2,Type2 p3,Type2 p4,void (*f)(std::remove_reference<decltype(*p1)>::type) );
Lets say that I have the following code in main:
int main() {
std::vector<int> v={1,2,3,4,5};
std::deque<int> d(5);
Fun(v.begin(),v.end(),d.begin(),d.end(), /* some lambda function */);
If you're only interested in the transformation, not in implementing a function with that type,
std::deque<int> d;
std::transform(v.begin(), v.end(), std::front_inserter(d), [](int x){return x * x;});
or
std::deque<int> d;
std::transform(v.rbegin(), v.rend(), std::back_inserter(d), [](int x){return x * x;});

Convert from Boost Hana Tuple to Std Vector

I am trying to create a std::vector from a boost::hana::tuple at compile-time like so:
boost::hana::tuple<std::string> namesString{ "Hello", "World" };
std::vector<std::string> namesStringVector{};
while(!(hana::is_empty(namesString)))
{
namesStringVector.emplace_back(hana::front(namesString));
hana::drop_front(namesString);
}
This clearly doesn't work because the while loop is not run at compile-time.
How do we achieve this effect in Boost::Hana? I.e. what compile-time Hana construct would allow us to perform this cast? I tried doing
namesStringVector = (std::vector<std::string>)namesString;
and
hana::to < std::vector < std::string > >(namesString);
But it tells me there does not exist such a cast in both cases.
In addition to the concerns that Louis addressed there are some other issues with how you are trying to use a tuple. Note that a tuple can not have its length or the types within it changed as types are completely immutable in C++ so you have to think in terms of pure functional programming.
Your call to is_empty will always return true, and drop_front can not change the input value, it only returns a new tuple with the front element removed. (in your case it would be tuple<> which is empty).
You might want to rethink your use case for wanting to convert a tuple to vector, but here is an example to hopefully get you started.
#include <boost/hana.hpp>
#include <iostream>
#include <string>
#include <vector>
namespace hana = boost::hana;
template <typename T>
constexpr auto to_vector = [](auto&& ...x) {
return std::vector<T>{std::forward<decltype(x)>(x)...};
};
int main() {
auto xs = hana::make_tuple("Hello", "World");
auto vec = hana::unpack(xs, to_vector<std::string>);
for (auto const& x : vec) {
std::cout << x << ' ';
}
std::cout << '\n';
}
Notes about list types:
std::vector has a run-time length and a single type for all
elements.
std::array has a compile-time length and a single type for all
elements.
hana::tuple has a compile-time length and any element can be any
type.
For starters, boost::hana::tuple<std::string> namesString{ "Hello", "World" }; doesn't make sense because your tuple only has one element but you try to initialize it with two.
Second, it doesn't really make sense to initialize a std::vector from a hana::tuple, since it implies that all the elements of the tuple have the same type. Instead, you should probably be using std::array. Hana is useful when you need heterogeneity (elements with different types), which you don't seem to need here. When you don't need heterogeneity, using std::array or similar tools will be much easier and natural than using Hana.

C++11, copying just one field into a vector

Say I have the following struct in C++
struct Foo {
double a;
int b;
};
And say I have a parameter to some function declared as follows:
const std::initializer_list<Foo> &args;
Is there an concise way to extract just one field from the elements in args to get, for instance, just an std::vector containing each b field from the original args list?
Of course, I know I could do this by just explicitly writing it out as a loop:
std::vector<int> result;
for(auto &x:args) {
result.push_back(x.b);
}
... but given that I can copy an entire initializer_list of any type to a like-typed vector in a single line of C++, just using functions like std::copy and std::back_inserter, I am wondering if there is a more elegant way to do this as well, using stl or C++11 facilities that may already exist.
You could use std::transform and add elements to the vector via std::back_inserter:
std::transform(std::begin(args), std::end(args), std::back_inserter(result),
[] (const Foo & foo) { return foo.b; });
If you find the lambda too verbose you can use std::mem_fn instead (credit goes to #StoryTeller).
std::transform(std::begin(args), std::end(args), std::back_inserter(result), std::mem_fn(&Foo::b));
But then again, your approach isn't necessary bad since it's pretty readable and does the job just fine (might have some performance issues tho).
One solution can be using linq++ like the following:
shared_ptr<vector<Foo>> foo_list;
// suppose foo_list is being filled
shared_ptr<vector> bs = from(foo_list).select(&_1 ->* &Foo::b).get();

Efficient way to return a std::vector in c++

How much data is copied, when returning a std::vector in a function and how big an optimization will it be to place the std::vector in free-store (on the heap) and return a pointer instead i.e. is:
std::vector *f()
{
std::vector *result = new std::vector();
/*
Insert elements into result
*/
return result;
}
more efficient than:
std::vector f()
{
std::vector result;
/*
Insert elements into result
*/
return result;
}
?
In C++11, this is the preferred way:
std::vector<X> f();
That is, return by value.
With C++11, std::vector has move-semantics, which means the local vector declared in your function will be moved on return and in some cases even the move can be elided by the compiler.
You should return by value.
The standard has a specific feature to improve the efficiency of returning by value. It's called "copy elision", and more specifically in this case the "named return value optimization (NRVO)".
Compilers don't have to implement it, but then again compilers don't have to implement function inlining (or perform any optimization at all). But the performance of the standard libraries can be pretty poor if compilers don't optimize, and all serious compilers implement inlining and NRVO (and other optimizations).
When NRVO is applied, there will be no copying in the following code:
std::vector<int> f() {
std::vector<int> result;
... populate the vector ...
return result;
}
std::vector<int> myvec = f();
But the user might want to do this:
std::vector<int> myvec;
... some time later ...
myvec = f();
Copy elision does not prevent a copy here because it's an assignment rather than an initialization. However, you should still return by value. In C++11, the assignment is optimized by something different, called "move semantics". In C++03, the above code does cause a copy, and although in theory an optimizer might be able to avoid it, in practice its too difficult. So instead of myvec = f(), in C++03 you should write this:
std::vector<int> myvec;
... some time later ...
f().swap(myvec);
There is another option, which is to offer a more flexible interface to the user:
template <typename OutputIterator> void f(OutputIterator it) {
... write elements to the iterator like this ...
*it++ = 0;
*it++ = 1;
}
You can then also support the existing vector-based interface on top of that:
std::vector<int> f() {
std::vector<int> result;
f(std::back_inserter(result));
return result;
}
This might be less efficient than your existing code, if your existing code uses reserve() in a way more complex than just a fixed amount up front. But if your existing code basically calls push_back on the vector repeatedly, then this template-based code ought to be as good.
It's time I post an answer about RVO, me too...
If you return an object by value, the compiler often optimizes this so it doesn't get constructed twice, since it's superfluous to construct it in the function as a temporary and then copy it. This is called return value optimization: the created object will be moved instead of being copied.
A common pre-C++11 idiom is to pass a reference to the object being filled.
Then there is no copying of the vector.
void f( std::vector & result )
{
/*
Insert elements into result
*/
}
If the compiler supports Named Return Value Optimization (http://msdn.microsoft.com/en-us/library/ms364057(v=vs.80).aspx), you can directly return the vector provide that there is no:
Different paths returning different named objects
Multiple return paths (even if the same named object is returned on
all paths) with EH states introduced.
The named object returned is referenced in an inline asm block.
NRVO optimizes out the redundant copy constructor and destructor calls and thus improves overall performance.
There should be no real diff in your example.
vector<string> getseq(char * db_file)
And if you want to print it on main() you should do it in a loop.
int main() {
vector<string> str_vec = getseq(argv[1]);
for(vector<string>::iterator it = str_vec.begin(); it != str_vec.end(); it++) {
cout << *it << endl;
}
}
follow code will works without copy constructors:
your routine:
std::vector<unsigned char> foo()
{
std::vector<unsigned char> v;
v.resize(16, 0);
return std::move(v); // move the vector
}
After, You can use foo routine for get the vector without copy itself:
std::vector<unsigned char>&& moved_v(foo()); // use move constructor
Result: moved_v size is 16 and it filled by [0]
As nice as "return by value" might be, it's the kind of code that can lead one into error. Consider the following program:
#include <string>
#include <vector>
#include <iostream>
using namespace std;
static std::vector<std::string> strings;
std::vector<std::string> vecFunc(void) { return strings; };
int main(int argc, char * argv[]){
// set up the vector of strings to hold however
// many strings the user provides on the command line
for(int idx=1; (idx<argc); ++idx){
strings.push_back(argv[idx]);
}
// now, iterate the strings and print them using the vector function
// as accessor
for(std::vector<std::string>::interator idx=vecFunc().begin(); (idx!=vecFunc().end()); ++idx){
cout << "Addr: " << idx->c_str() << std::endl;
cout << "Val: " << *idx << std::endl;
}
return 0;
};
Q: What will happen when the above is executed? A: A coredump.
Q: Why didn't the compiler catch the mistake? A: Because the program is
syntactically, although not semantically, correct.
Q: What happens if you modify vecFunc() to return a reference? A: The program runs to completion and produces the expected result.
Q: What is the difference? A: The compiler does not
have to create and manage anonymous objects. The programmer has instructed the compiler to use exactly one object for the iterator and for endpoint determination, rather than two different objects as the broken example does.
The above erroneous program will indicate no errors even if one uses the GNU g++ reporting options -Wall -Wextra -Weffc++
If you must produce a value, then the following would work in place of calling vecFunc() twice:
std::vector<std::string> lclvec(vecFunc());
for(std::vector<std::string>::iterator idx=lclvec.begin(); (idx!=lclvec.end()); ++idx)...
The above also produces no anonymous objects during iteration of the loop, but requires a possible copy operation (which, as some note, might be optimized away under some circumstances. But the reference method guarantees that no copy will be produced. Believing the compiler will perform RVO is no substitute for trying to build the most efficient code you can. If you can moot the need for the compiler to do RVO, you are ahead of the game.
vector<string> func1() const
{
vector<string> parts;
return vector<string>(parts.begin(),parts.end()) ;
}
This is still efficient after c++11 onwards as complier automatically uses move instead of making a copy.