Why iota_view allows different integer template arguments? - c++

I have the following broken code, from what I can tell problem here is that iota(0, n)
returns me a iota_view<int,int64> and then obviously int can never be int64 that is greater than INT_MAX.
Easy fix is to just use iota(0LL, n), but that seems error prone.
int main() {
const int64_t n = 16LL*1024*1024*1024;
auto ints = std::ranges::views::iota(0, n) |
std::views::transform([](int64_t x) { return x * 10; });
for (int64_t lookup : {49LL, 50LL, 51LL}) {
const auto it = std::ranges::lower_bound(ints, lookup);
if (it != ints.end()) {
std::cout << *it << std::endl;
std::cout << *it.base() << std::endl;
}
}
}
My best guess is that iota_view wants to work with "weird" second type, like some kind of +INF type, so that is why it needs 2 types, and nobody thought of forcing the first argument to match the second one if they are both ints.

Related

Using Lambda Function with find_if C++20

I am getting a syntax error on the line
if (auto result = ranges::find_if(height.begi with a red squiggly line under find_if:
no instance of overloaded function matches the argument list
auto is_gt_or_eq = [height, i](int x) { height[x] >= height[i]; };
if (auto result = ranges::find_if(height.begin(), height.end(), is_gt_or_eq); result != height.end()) {
std::cout << "First larger or equal to element in height: " << *result << '\n';
}
else {
std::cout << "No larger or equal to element in height\n";
}
I found this similar code on cppreference, and it does run:
auto is_even = [](int x) { return x % 2 == 0; };
if (auto result = ranges::find_if(height.begin(), height.end(), is_even); result != height.end()) {
std::cout << "First even element in height: " << *result << '\n';
}
else {
std::cout << "No even elements in height\n";
}
I believe the error is in this line of code:
auto is_gt_or_eq = [height, i](int x) { height[x] >= height[i]; };
To start with, you forgot the return keyword for the return statement. So your lambda is returning void by default, thus not a valid predicate. The library won't allow you to call its function due to this mismatch.
Beyond that, x is (a copy of) the element of height, not an index of the container. There is no need to access the container again for the element in the lambda. So, the simplest fix is
auto is_gt_or_eq = [height, i](int x) { return x >= height[i]; };
There's also no need to constantly re-access height[i] in the lambda. It's not a bad idea to just capture that value instead.
auto is_gt_or_eq = [hi = height[i]](int x) { return x >= hi; };
Your lambda is now smaller, more inline-able and (to me at least) more readable.

Generator called twice in C++20 views pipeline [duplicate]

This question already has an answer here:
Why C++ ranges "transform -> filter" calls transform twice for values that match the filter's predicate?
(1 answer)
Closed 1 year ago.
Here in a simple pipeline of views adaptors, there is the gen function called to generate a sequence of values (using an internal state) and then a filter on it.
What is surprising and counterintuitive (at least for me) is the fact that the generator function is called twice at each iteration, so that the next check on the same filter fails (the filtered value is not reused in the pipeline).
Do you have an idea if this is the correct expected behavior (and why)?
Tested with libstdc++ in GCC 10.3, 11.1 & trunk (code) and range-v3 with GCC & clang (code).
int main() {
int n = 0;
auto gen = [&n]() {
auto result = ++n;
std::cout << "Generate [" << result << "]\n";
return result;
};
auto tmp =
ranges::views::iota(0)
| ranges::views::transform([gen](auto &&) { return gen(); })
| ranges::views::filter([](auto &&i) {
std::cout << "#1 " << i << " " << (i % 2) << "\n";
return (i % 2) == 1;
});
for (auto &&i : tmp | ranges::views::take(1)) {
std::cout << "#2 " << i << " " << ((i % 2) == 1) << "\n";
assert(((i % 2) == 1));
}
}
NB: if gen function is written as mutable with an internal state, it does not compile:
auto gen = [n=0]() mutable {
auto result = ++n;
std::cout << "Generate [" << result << "]\n";
return result;
};
(and I know that pure functions are better)
Do you have an idea if this is the correct expected behavior (and why)?
Yes: this is the expected behavior. It is an inherent property of the iteration model where we have operator* and operator++ as separate operations.
filter's operator++ has to look for the next underlying iterator that satisfies the predicate. That involves doing *it on transform's iterator which involves invoking the function. But once we find that next iterator, when we read it again, that will again invoke the transform. In a code snippet:
decltype(auto) transform_view<V, F>::iterator::operator*() const {
return invoke(f_, *it_);
}
decltype(auto) filter_view<V, P>::iterator::operator*() const {
// reading through the filter iterator just reads
// through the underlying iterator, which in this
// case means invoking the function
return *it_;
}
auto filter_view<V, P>::iterator::operator++() -> iterator& {
for (++it_; it_ != ranges::end(parent_->base_); ++it_) {
// when we eventually find an iterator that satisfies this
// predicate, we will have needed to read it (which calls
// the functions) and then the next operator* will do
// that same thing again
if (invoke(parent_->pred_, *it_))) {
break;
}
}
return *this;
}
The result is that we invoke the function twice on every element that satisfies the predicate.
The workaround is to either just not care (have the transform be either cheap enough that invoking it twice doesn't matter or the filter be sufficiently rare that the amount of duplicate transforms don't matter or both) or do add a caching layer into your pipeline.
There's no caching view in C++20 Ranges, but there is one in range-v3 named views::cache1:
ranges::views::iota(0)
| ranges::views::transform(f)
| ranges::views::cache1
| ranges::views::filter(g)
This ensures that f only gets invoked at most once per element, at the cost of having to deal with an element cache and downgrading your range to only be an input range (where before it was bidirectional).

Comparing arrays of objects with arrays of fields of objects

Is there a good way to compare arr[i].A to A[i] and arr[i].B to B?
int A[10], B[10];
class Foo {
int A, B;
};
Foo arr[10];
I could do the following:
for (i=0;i<10;i++) {
if (A[i] == arr[i].A) {}
if (B[i] == arr[i].B) {}
}
But, this is painful especially if there are a lot of fields, and the if() conditional does the same thing over and over, there will be a lot of code duplication. What I really want to do is parametrize this somehow and call a function like (test(A,arr)). I guess I can solve this by using #define macros, but that seems ugly.
Any suggestions?
Also I want to avoid creating a new array of Foo objects because I don't want to create new objects that may have many fields I don't care about, also I may want to compare different subsets of fields.
IF the ranges are of equal size you can use std::equal with a predicate (or a lambda):
bool CompA( int lhs, Foo rhs ){
return lhs == rhs.A;
};
...
// to check for equality
bool result = std::equal( A, A + 10, arr, CompA );
...
// to see where the mismatch is
std::pair< int*, Foo* > result = std::mismatch( A, A + 10, arr, CompA );
size_t index = result.first - A;
if( index < 10 ){
std::cout << "Mismatch at index " << index << " A = " << *result.first << " Foo.A = " << (*result.second).A << std::endl;
}
There are standard-library algorithms for doing operations on containers (including arrays, kinda) but using them typically produces code that's harder to read and maintain, and no shorter or more efficient, than straightforward loops.
However, it sounds as if you might want to know about pointers-to-members.
bool all_equal(int Foo::* member, const Foo * obj_array, const int * elem_array, size_t n) {
for (int i=0; i<n; ++i) {
if (obj_array[i].*member != elem_array[i]) return false;
}
return true;
}
...
if (all_equal(&Foo::A, arr, A, 10) && all_equal(&Foo::*B, arr, B, 10)) ...
although actually you should probably generalize it:
template<typename T, typename E>
bool all_equal(E T::* member, const T* obj_array, const E* elem_array, size_t n) {
for (int i=0; i<n; ++i) {
if (obj_array[i].*member != elem_array[i]) return false;
}
return true;
}
(Danger: all code above is untested and may consist entirely of bugs.)

multimap accumulate values

I have a multimap defined by
typedef std::pair<int, int> comp_buf_pair; //pair<comp_t, dij>
typedef std::pair<int, comp_buf_pair> node_buf_pair;
typedef std::multimap<int, comp_buf_pair> buf_map; //key=PE, value = pair<comp_t, dij>
typedef buf_map::iterator It_buf;
int summ (int x, int y) {return x+y;}
int total_buf_size = 0;
std::cout << "\nUpdated buffer values" << std::endl;
for(It_buf it = bufsz_map.begin(); it!= bufsz_map.end(); ++it)
{
comp_buf_pair it1 = it->second;
// max buffer size will be summ(it1.second)
//total_buf_size = std::accumulate(bufsz_map.begin(), bufsz_map.end(), &summ); //error??
std::cout << "Total buffers required for this config = " << total_buf_size << std::endl;
std::cout << it->first << " : " << it1.first << " : " << it1.second << std::endl;
}
I would like to sum all the values pointed by it1.second
How can the std::accumulate function access the second iterator values?
Your issue is with the summ function, you actually need something better than that to be able to handle 2 mismatched types.
If you're lucky, this could work:
int summ(int x, buf_map::value_type const& v) { return x + v.second; }
If you're unlucky (depending on how accumulate is implemented), you could always:
struct Summer
{
typedef buf_map::value_type const& s_type;
int operator()(int x, s_type v) const { return x + v.second.first; }
int operator()(s_type v, int x) const { return x + v.second.first; }
};
And then use:
int result = std::accumulate(map.begin(), map.end(), 0, Summer());
I think you'll just need to change your summ function to take the map value_type instead. This is totally untested but it should give the idea.
int summ (int x, const buf_map::value_type& y)
{
return x + y.second;
}
And call it:
total_buf_size = std::accumulate(bufsz_map.begin(), bufsz_map.end(), 0, &summ);
Why do you mess about with pairs containing pairs? It is too complicated and you'll wind up making errors. Why not define a struct?
Accumulate is a generalization of summation: it computes the sum (or some other binary operation) of init and all of the elements in the range [first, last).
... The result is first initialized to init. Then, for each iterator i in [first, last), in order from beginning to end, it is updated by result = result + *i (in the first version) or result = binary_op(result, *i) (in the second version).
Sgi.com
Your attempt was neither first or second version, you missed the init part
total_buf_size = std::accumulate(bufsz_map.begin(), bufsz_map.end(), 0, &summ);

Is it possible to declare two variables of different types in a for loop?

Is it possible to declare two variables of different types in the initialization body of a for loop in C++?
For example:
for(int i=0,j=0 ...
defines two integers. Can I define an int and a char in the initialization body? How would this be done?
No - but technically there is a work-around (not that i'd actually use it unless forced to):
for(struct { int a; char b; } s = { 0, 'a' } ; s.a < 5 ; ++s.a)
{
std::cout << s.a << " " << s.b << std::endl;
}
Not possible, but you can do:
float f;
int i;
for (i = 0,f = 0.0; i < 5; i++)
{
//...
}
Or, explicitly limit the scope of f and i using additional brackets:
{
float f;
int i;
for (i = 0,f = 0.0; i < 5; i++)
{
//...
}
}
C++17: Yes! You should use a structured binding declaration. The syntax has been supported in gcc and clang since gcc-7 and clang-4.0 (clang live example). This allows us to unpack a tuple like so:
for (auto [i, f, s] = std::tuple{1, 1.0, std::string{"ab"}}; i < N; ++i, f += 1.5) {
// ...
}
The above will give you:
int i set to 1
double f set to 1.0
std::string s set to "ab"
Make sure to #include <tuple> for this kind of declaration.
You can specify the exact types inside the tuple by typing them all out as I have with the std::string, if you want to name a type. For example:
auto [vec, i32] = std::tuple{std::vector<int>{3, 4, 5}, std::int32_t{12}}
A specific application of this is iterating over a map, getting the key and value,
std::unordered_map<K, V> m = { /*...*/ };
for (auto& [key, value] : m) {
// ...
}
See a live example here
C++14: You can do the same as C++11 (below) with the addition of type-based std::get. So instead of std::get<0>(t) in the below example, you can have std::get<int>(t).
C++11: std::make_pair allows you to do this, as well as std::make_tuple for more than two objects.
for (auto p = std::make_pair(5, std::string("Hello World")); p.first < 10; ++p.first) {
std::cout << p.second << '\n';
}
std::make_pair will return the two arguments in a std::pair. The elements can be accessed with .first and .second.
For more than two objects, you'll need to use a std::tuple
for (auto t = std::make_tuple(0, std::string("Hello world"), std::vector<int>{});
std::get<0>(t) < 10;
++std::get<0>(t)) {
std::cout << std::get<1>(t) << '\n'; // cout Hello world
std::get<2>(t).push_back(std::get<0>(t)); // add counter value to the vector
}
std::make_tuple is a variadic template that will construct a tuple of any number of arguments (with some technical limitations of course). The elements can be accessed by index with std::get<INDEX>(tuple_object)
Within the for loop bodies you can easily alias the objects, though you still need to use .first or std::get for the for loop condition and update expression
for (auto t = std::make_tuple(0, std::string("Hello world"), std::vector<int>{});
std::get<0>(t) < 10;
++std::get<0>(t)) {
auto& i = std::get<0>(t);
auto& s = std::get<1>(t);
auto& v = std::get<2>(t);
std::cout << s << '\n'; // cout Hello world
v.push_back(i); // add counter value to the vector
}
C++98 and C++03 You can explicitly name the types of a std::pair. There is no standard way to generalize this to more than two types though:
for (std::pair<int, std::string> p(5, "Hello World"); p.first < 10; ++p.first) {
std::cout << p.second << '\n';
}
You can't declare multiple types in the initialization, but you can assign to multiple types E.G.
{
int i;
char x;
for(i = 0, x = 'p'; ...){
...
}
}
Just declare them in their own scope.
I think best approach is xian's answer.
but...
# Nested for loop
This approach is dirty, but can solve at all version.
so, I often use it in macro functions.
for(int _int=0, /* make local variable */ \
loopOnce=true; loopOnce==true; loopOnce=false)
for(char _char=0; _char<3; _char++)
{
// do anything with
// _int, _char
}
Additional 1.
It can also be used to declare local variables and initialize global variables.
float globalFloat;
for(int localInt=0, /* decalre local variable */ \
_=1;_;_=0)
for(globalFloat=2.f; localInt<3; localInt++) /* initialize global variable */
{
// do.
}
Additional 2.
Good example : with macro function.
(If best approach can't be used because it is a for-loop-macro)
#define for_two_decl(_decl_1, _decl_2, cond, incr) \
for(_decl_1, _=1;_;_=0)\
for(_decl_2; (cond); (incr))
for_two_decl(int i=0, char c=0, i<3, i++)
{
// your body with
// i, c
}
# If-statement trick
if (A* a=nullptr);
else
for(...) // a is visible
If you want initialize to 0 or nullptr, you can use this trick.
but I don't recommend this because of hard reading.
and it seems like bug.
See "Is there a way to define variables of two types in for loop?" for another way involving nesting multiple for loops. The advantage of the other way over Georg's "struct trick" is that it (1) allows you to have a mixture of static and non-static local variables and (2) it allows you to have non-copyable variables. The downside is that it is far less readable and may be less efficient.
Also you could use like below in C++.
int j=3;
int i=2;
for (; i<n && j<n ; j=j+2, i=i+2){
// your code
}
Define a macro:
#define FOR( typeX,x,valueX, typeY,y,valueY, condition, increments) typeX x; typeY y; for(x=valueX,y=valueY;condition;increments)
FOR(int,i,0, int,f,0.0, i < 5, i++)
{
//...
}
Just remember, your variable scopes will not be within the for loop this way either.