Is There a Compact Equivalent to Python Range() in C++/Stl

Is there a compact equivalent to Python range() in C++/STL

In C++11, there's std::iota:

#include <vector>
#include <numeric> //std::iota

int main() {
std::vector<int> x(10);
std::iota(std::begin(x), std::end(x), 0); //0 is the starting number
}

C++20 introduced a lazy version (just like Python) as part of the ranges library:

#include <iostream>
#include <ranges>

namespace views = std::views;

int main() {
for (int x : views::iota(0, 10)) {
std::cout << x << ' '; // 0 1 2 3 4 5 6 7 8 9
}
}

C++ range/xrange equivalent in STL or boost?

Boost has counting_iterator as far as I know, which seems to allow only incrementing in steps of 1. For full xrange functionality you might need to implement a similar iterator yourself.

All in all it could look like this (edit: added an iterator for the third overload of xrange, to play around with boost's iterator facade):

#include <iostream>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/foreach.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <cassert>

template <class T>
boost::iterator_range<boost::counting_iterator<T> > xrange(T to)
{
//these assertions are somewhat problematic:
//might produce warnings, if T is unsigned
assert(T() <= to);
return boost::make_iterator_range(boost::counting_iterator<T>(0), boost::counting_iterator<T>(to));
}

template <class T>
boost::iterator_range<boost::counting_iterator<T> > xrange(T from, T to)
{
assert(from <= to);
return boost::make_iterator_range(boost::counting_iterator<T>(from), boost::counting_iterator<T>(to));
}

//iterator that can do increments in steps (positive and negative)
template <class T>
class xrange_iterator:
public boost::iterator_facade<xrange_iterator<T>, const T, std::forward_iterator_tag>
{
T value, incr;
public:
xrange_iterator(T value, T incr = T()): value(value), incr(incr) {}
private:
friend class boost::iterator_core_access;
void increment() { value += incr; }
bool equal(const xrange_iterator& other) const
{
//this is probably somewhat problematic, assuming that the "end iterator"
//is always the right-hand value?
return (incr >= 0 && value >= other.value) || (incr < 0 && value <= other.value);
}
const T& dereference() const { return value; }
};

template <class T>
boost::iterator_range<xrange_iterator<T> > xrange(T from, T to, T increment)
{
assert((increment >= T() && from <= to) || (increment < T() && from >= to));
return boost::make_iterator_range(xrange_iterator<T>(from, increment), xrange_iterator<T>(to));
}

int main()
{
BOOST_FOREACH(int i, xrange(10)) {
std::cout << i << ' ';
}
BOOST_FOREACH(int i, xrange(10, 20)) {
std::cout << i << ' ';
}
std::cout << '\n';
BOOST_FOREACH(int i, xrange(0, 46, 5)) {
std::cout << i << ' ';
}
BOOST_FOREACH(int i, xrange(10, 0, -1)) {
std::cout << i << ' ';
}
}

As others are saying, I don't see this buying you much over a normal for loop.

What's the equivalent to Mathematica's Range[] function in C++?

None in the standard library, but from boost::range:

#include <iostream>
#include <iterator>
#include <boost/range/irange.hpp>
#include <boost/range/algorithm/copy.hpp>

int main()
{
boost::copy(boost::irange(0, 11),
std::ostream_iterator<int>(std::cout, " "));
}

Output:
0 1 2 3 4 5 6 7 8 9 10

Python-like loop enumeration in C++

As @Kos says, this is such a simple thing that I don't really see the need to simplify it further and would personally just stick to the traditional for loop with indices, except that I'd ditch std::vector<T>::size_type and simply use std::size_t:

for(std::size_t i = 0; i < v.size(); ++i)
foo(v[i], i);

I'm not too keen on solution 2. It requires (kinda hidden) random access iterators which wouldn't allow you to easily swap the container, which is one of the strong points of iterators. If you want to use iterators and make it generic (and possibly incur a performance hit when the iterators are not random access), I'd recommend using std::distance:

for(auto it(v.begin()); it != v.end(); ++it)
foo(*it, std::distance(it, v.begin());

n={0,1,...,n-1} in C++

It can't be done. From section 6.5.4 of the draft of the C++ 14 standard (but C++11 will be very similar)

begin-expr and end-expr are determined as follows:

(1.1) — if _RangeT is an array type, [...];

Well, this one obviously doesn't apply. An int isn't an array

(1.2) — if _RangeT is a class type, [...]

Nope, this doesn't apply either.

(1.3) — otherwise, begin-expr and end-expr are begin(__range) and end(__range), respectively,

Oo! This looks hopeful. You may need to move begin and end into the global namespace, but still...

where begin
and end are looked up in the associated namespaces (3.4.2). [ Note: Ordinary unqualified lookup (3.4.1)
is not performed. — end note ]

(emphasis mine). Bother! There aren't any namespaces associated with int. Specifically, from section 3.4.2

— If T [int in our case] is a fundamental type, its associated sets of namespaces and classes are both empty.

The only workround is to write a class range which has a suitable begin and end method. Then you could write the very pythonic:

for (int i : range(5))

How to use functor which returns two value with standard library functions?

is possible to return two values from a functor (for example a tuple)

yes ,it is ,but you need also proper

operator bool()

As I understood, you want something like this:

#include <utility>
#include <algorithm>
#include <iterator>
#include <functional>

struct Pair{

bool b;
uint32_t data;

operator bool()const{
return this->b;
}

const Pair & isIdd(uint32_t p){
if (p == this-> data) this->b = true;
return *this ;
}

Pair(bool b , uint32_t data){
this-> b = b;
this->data = data;
}

};

int main(){
using namespace std::placeholders;
Pair p(0,0);
std::vector<uint32_t> vct {2};
auto it = vct.begin ();
auto b = std::bind(&Pair::isIdd,_1,_2);
std::find_if(vct.begin (),vct.end (),b(p,*it++ ));
}

But what is here is not relevant to the task set as the solution of the equation.
If this fits to you and you really want to use find_if as this ,turn it into template and somehow store found data.

Most efficient/elegant way to clip a number?

What about boring, old, readable, and shortest yet:

float clip(float n, float lower, float upper) {
return std::max(lower, std::min(n, upper));
}

?

This expression could also be 'genericized' like so:

template <typename T>
T clip(const T& n, const T& lower, const T& upper) {
return std::max(lower, std::min(n, upper));
}

Update

Billy ONeal added:

Note that on windows you might have to define NOMINMAX because they define min and max macros which conflict

Implement C++ template for generating an index sequence with a given range

The way you defined index_range (before the question was edited) the answer is simply:

template<std::size_t Min, std::size_t Max>
using make_index_range = index_range<Min, Max>;

Which is not very useful.

So I'm going to assume you mean make_index_range<5, 9> will give index_sequence<5, 6, 7, 8>, which can be done like this:

#include <utility>

template<std::size_t N, std::size_t... Seq>
constexpr std::index_sequence<N + Seq ...>
add(std::index_sequence<Seq...>)
{ return {}; }

template<std::size_t Min, std::size_t Max>
using make_index_range = decltype(add<Min>(make_index_sequence<Max-Min>()));

Or if you want make_index_range to be a class template, define add as above and then:

template<std::size_t Min, std::size_t Max>
struct make_index_range {
using type = decltype(add<Min>(make_index_sequence<Max-Min>()));
};

(But with this you have to use make_index_range<5, 9>::type so the alias template is probably better, and closer to how make_index_sequence works.)



Related Topics



Leave a reply



Submit