ericniebler / range-v3 Goto Github PK
View Code? Open in Web Editor NEWRange library for C++14/17/20, basis for C++20's std::ranges
License: Other
Range library for C++14/17/20, basis for C++20's std::ranges
License: Other
Currently function objects like for example begin
and end
are not conditionally noexcept
.
The draft N3279 is IMO extremely conservative with the use of noexcept
.
Shouldn't the noexcept
specification of user-defined types be propagated by the library as far as it can by being conditionally noexcept
?
For example if a user defined type implements noexcept
begin
and end
, and then uses the range library in generic code that is conditionally noexcept
, this code will be always noexcept(false)
unless the range library propagates noexcept
correctly.
OTOH propagating noexcept
correctly in generic code is a true PITA and IMO a huge burden for library authors.
This library has a great potential to become popular. It also chooses the right naming, like 'requires'. And these two things together may constitute a problem. C++ Extensions for Concepts (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4040.pdf) likely to be published son (2015?) make 'requires' and 'concept' keywords, and will collide with this library. In the best case, this library will break in concept-enabled compilers. In the worst, if your library becomes sufficiently popular, it will prevent the addition of keyword 'requires' and for backward compatibility reasons C++ will be forced to use some obscure substitute, like 'concept_requires'.
It is not really an 'issue' with this library, but still a change worth considering.
I always thought that the "find_if / count_if / ... _if / ... _if_not" algorithms were a workaround for the lack of view::filter
(an idiom I commonly use with Boost.Range v2 is count(rng | filter1 | filter2)
). It seems to be the case for the "_n" algorithms too (we have view::counted
, view::delimited
, view::take
, view::take_while
...).
I think that it is worth to discuss if they are still needed.
For example:
count_if
returns an iterator_difference
so it should be replaceable by count( range | view::filter(f))
in all cases.find_if
returns an iterator so it can't be replaced since it would then return an iterator into a dead range.I just had a go at compiling with the VS 2015 preview, but I get tons of:
error C3546: '...': there are no parameter packs available to expand act.concepts meta.hpp 899
For example, it would be this line:
template<typename ...List, typename Fun>
struct transform_<list<List...>, Fun, void>
{
using type = list<apply<Fun, List>...>; // <---
};
While I have some (limited) knowledge about templates and variadics, I have no clue how to even approach this, even with this SO post, which seems quite related.
I understand that this library is more of a proof-of-concept, (and I think the author uses gcc under Windows ;-) ), and yea, VS still lacks behind a lot in terms of C++11/14. But I think VS 2015 would be a really really reasonable and awesome target for this library to run on. I would love to use it!
When compiling two cpp files, each including "all.hpp", then 42 duplicate symbols are detected by the linker. This is the case for both "gcc (MacPorts gcc49 4.9.1_1) 4.9.1" and "Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)", on OS X 10.10.
Repro steps:
Add file range-v3/include/a.cpp:
int main(int argc, const char* argv[]){
return 0;
}
Add file range-v3/include/b.cpp:
In directory range-v3/include/ compile using
/usr/bin/clang -I. -std=c++11 a.cpp b.cpp
or
gcc -I. -std=c++11 a.cpp b.cpp
Result:
[...] ld: 42 duplicate symbols for architecture x86_64 [...]
I get a lot of un-used functions, variables, and shadowing warnings.
I'm willing to fix them but want to discuss what is the best way to proceed:
Or maybe there is a better way.
FWIW i'm compiling with clang/libc++ HEAD and the following flags:
"-Wall" "-Wextra" "-std=c++1y" "-stdlib=libc++"
"-pedantic" "-Wshadow" "-Woverloaded-virtual"
"-pedantic-errors" "-Wcast-align" "-Wcomment" "-Wcast-qual"
"-Wchar-subscripts" "-Wdisabled-optimization" "-Wfloat-equal" "-Wformat=2"
"-Winvalid-pch" "-Wformat-nonliteral" "-Wformat-security" "-Wformat-y2k"
"-Wimport" "-Winit-self" "-Winline" "-Wreturn-type" "-Wmissing-braces"
"-Wmissing-field-initializers" "-Wmissing-include-dirs" "-Wredundant-decls"
"-Wpacked" "-Wparentheses" "-Wpointer-arith" "-Wsequence-point"
"-Wsign-compare" "-Wstack-protector" "-Wstrict-aliasing=2" "-Wswitch"
"-Wswitch-default" "-Wtrigraphs" "-Wuninitialized" "-Wunknown-pragmas"
"-Wunreachable-code" "-Wunused" "-Wunused-function" "-Wunused-label"
"-Wunused-parameter" "-Wunused-value" "-Wunused-variable"
"-Wvariadic-macros" "-Wvolatile-register-var" "-Wwrite-strings"
"-Woverloaded-virtual" "-Wsign-promo" "-Wstrict-overflow=5"
"-Wswitch-default"
"-fdiagnostics-show-template-tree" "-ftemplate-backtrace-limit=0"
"-Wno-attributes"
The name is terrible. And it can't generate a finite range of integers. It pretty much sucks. See #16 for more discussion.
Examples do not run when using ctest
and I think it is important to run them with the address sanitizer (and other sanitizers in the future).
I think that the easiest thing is to just also add them as tests such that they run when ctest
is executed.
I find both filter
and remove_if
useful. Replacing filter(pred)
with remove_if(not(pred))
makes IMO the code less readable. The intent is just harder to understand due to the double negation: do something on the elements that are not the elements for which the predicate is not true (my brain melts).
N4009 - Uniform container erasure defines erase_if
which seems analogous to Boost.Range v2 erase_remove_if
container algorithm.
Hi Eric,
First, thanks for your great work. I like ranges and your library :)
I got interested in this comment (in PR #23):
Initializer list literals (e.g. used in-situ) are never "temporary". They're like string constants.
since if this is true it might be nice to propose allowing braced-init-lists in binary operators (e.g. {1, 2, 3} | view::xxxx
) to C++17.
So I double-checked the comment about the lifetime, but I couldn't find parts that support this. N3936 [dcl.init.list] says
p5
An object of type std::initializer_list is constructed from an initializer list as if the implementation allocated a temporary array [...]p6
The array has the same lifetime as any other temporary object (12.2), except that initializing an initializer_list object from the array extends the lifetime of the array exactly like binding a reference to a temporary. [...]
Thus, the lifetime of the underlying array in
// is_heap_until.cpp
S const * r = ranges::is_heap_until({S{1}, S{0}, S{0}, S{0}, S{0}, S{0}, S{1}}, std::greater<int>(), &S::i);
CHECK((r-1)->i == 1);
CHECK(r->i == 0);
ends before CHECK(...)
. Doesn't (r-1)->i == 1
(and r->i == 0
) lead to undefined behavior?
(c.f. (ranges::is_heap_until({S{1}, S{0}, S{0}, S{0}, S{0}, S{0}, S{1}}, std::greater<int>(), &S::i) - 1)->i == 1
doesn't have lifetime issue.)
Thanks,
Michel
for (auto i : istream<std::string>(std::cin) | view::take(3))
std::cout << i << '\n';
for (auto i : istream<std::string>(std::cin) | view::take(3))
std::cout << i << '\n';
I would expect that snippet to print 6 consecutive strings from standard input. Instead, it prints 3, skips one, and then prints the next 3.
Consider the following code:
auto odd_ints = ranges::view::ints(1)|ranges::view::remove_if([](auto&& x){return x%2==0;});
It compiles on gcc 4.9.1 (from macports "gcc49 @4.9.1_1"). Clang pre 3.6 (from macports clang-3.6 @3.6-r222672_0+analyzer+arm_runtime+assertions) does however fail with the error:
src/main.cpp:114:86: error: invalid operands to binary expression ('ranges::v3::iota_view<int, void>' and 'int')
auto odd_ints = ranges::view::ints(1)|ranges::view::remove_if([](auto&& x){return x%2==0;});
~^~
Thus, x seems to be of type ranges::v3::iota_view<int, void>
and not int
(or const int&
).
Changing the argument of the filter predicate to int
makes it compile:
auto odd_ints = ranges::view::ints(1)|ranges::view::remove_if([](int x){return x%2==0;});
While interestingly, trying to explicitly convert x to int does not:
src/main.cpp:114:86: error: no matching conversion for C-style cast from 'ranges::v3::iota_view<int, void>' to 'int'
auto odd_ints = ranges::view::ints(1)|ranges::view::remove_if([](auto&& x){return ((int)x)%2==0;});
^~~~~~
Is this a clang-bug which should be reported(?), or is it a ranges-bug which exploits non-standard behavior of gcc?
When I was fixing doc/comment typo, I found that some files
(LICENSE
, include/range/v3/view/remove_if.hpp
and test/view/CMakeLists.txt
)
mix up CRLF and LF line endings.
For example, the last commit (639d31d)
resolved CRLF/LF mix-up in CMakeLists.txt
(you can see spurious changes in the linked page) but introduced a new mix-up in test/view/CMakeLists.txt
.
Maybe .gitattributes
can help avoiding these mix-up?
Concept-check that I's value type is CopyConstructable and MoveAssignable.
Right now, if I try to write a function that returns the unique items like this:
template<class Range>
auto unique_items(Range& r)
{
std::unordered_set<range_value_t<Range>> values;
return view::for_each(r, [=](auto&& x) mutable
{
return yield_if(values.insert(x).second, x);
});
}
int main()
{
std::vector<int> ints = { 1, 1, 2, 3, 1, 2, 4, 5, 5 };
auto unique_ints = unique_items(ints);
std::cout << "First: " << std::endl;
RANGES_FOR(int i, unique_ints)
{
std::cout << i << std::endl;
}
std::cout << "Second: " << std::endl;
RANGES_FOR(int i, unique_ints)
{
std::cout << i << std::endl;
}
}
The first loop prints the unique items, but the second time it iterates its empty. Of course, this is partly due to using a mutable
lambda. It would nice to be able to inject variables and not have to use a mutable
lambda, perhaps write something like a let
mechanism:
template<class Range>
auto unique_items(Range& r)
{
return view::for_each(r,
[]{ return std::unordered_set<range_value_t<Range>>(); },
[=](auto&& x, auto& values)
{
return yield_if(values.insert(x).second, x);
});
}
I not sure the best way to write it would be.
Or perhaps, there is another way where the range could be made lazy, although a mutable
lambda would still be needed:
template<class Range>
auto unique_items(Range& r)
{
return lazy_range([&]
{
std::unordered_set<range_value_t<Range>> values;
return view::for_each(r, [=](auto&& x) mutable
{
return yield_if(values.insert(x).second, x);
});
});
}
The tests for random_shuffle assumes that two separate calls to the algorithm on equal ranges will produce different permutations (or at least, that the chances of them producing the same permutation on ranges of size 100 is small enough to safely ignore).
test\algorithm\random_shuffle.cpp(55)
CHECK(!ranges::equal(ia, ib));
This assumption does not hold for me (mingw32, gcc 4.9.1). I'm pretty sure it's due to the fact that random_shuffle constructs a new random_device every time it is called, and uses that to seed the engine. But on my system, random_device is deterministic (as I believe it is allowed to be), so this results in the same seed every time.
Perhaps random_shuffle should use a persistent random_device? Either as static local to the operator, or as a data member of random_shuffle_fn.
For certain classes of Ranges/Iterables, there may be ways to implement for_each that are easier to optimize (and auto-vectorize) for the compiler and thus gives faster code.
My use-case is a chunked_vector, being a vector of vectors, where for_each(chunked_vector<T>& d,F f)
is essentially implemented as for_each(d.chunks_,[f&](vector<T>& chunk){for_each(chunk,f);})
.
The inner loop here probably becomes easier to auto-vectorize than one based on somewhat complicated iterators.
So, the question is: is there a customization point in ranges that make it possible to add such specializations? Otherwise, this is a feature request for such customization points.
For example: view::while_true(range, predicate)
returns a slice of range
starting at its beginning and ending at the first element of the range for which the predicate
is false.
It does the same thing as view::delimit
, but works on a predicate instead of on value equality.
Bikeshed: view::while_true
, view::until
I have tried to run the test using CMake but I have not reached :(
I have added a jamfile in my forked repository
viboes@2cf8b8a
How I can do a pull request?
I found an instance where ranges::sort(vec)
fails to compile but std::sort(vec.begin(), vec.end())
compiles. The type of vec
is std::vector<rule_t>
, and the definition of rule_t
is:
struct rule_t {
rule_t(std::string lhs, std::vector<std::string> rhs, double prob)
: lhs_{std::move(lhs)}, rhs_{std::move(rhs)}, prob_{prob}
{}
std::string const & lhs() const { return lhs_; }
std::vector<std::string> const & rhs() const { return rhs_; }
double const & prob() const { return prob_; }
private:
std::string lhs_;
std::vector<std::string> rhs_;
double prob_;
};
bool operator<(rule_t const &left, rule_t const &right) {
return std::tie(left.lhs(), left.rhs()) < std::tie(right.lhs(), right.rhs());
}
This is because the concept requirements on ordered_less
(and ranges::less
as well) are stricter than the (non-existent) ones in the standard library.
Should ranges::sort
default to requiring TotallyOrdered? ranges::less
may be less (ha ha) surprising to users. (In my case I can and will just define operator==
etc, but I can imagine there may be cases where that is not desirable.)
Is it necessary for less
to require the presence of operators >
, <=
, and >=
? I understand that all of these operators should be defined if any are, but it still feels surprising that less
is not callable on a type that defines operator<
. (At least when we do get concepts the error messages will finally be understandable).
RandomAccessRanges
support O(1) access to all of its elements, however, there is no syntax sugar for this yet (via the []
and the ()
operators).
std::vector<int> v {1, 2, 3, 4};
auto rng = ranges::range(ranges::begin(v), ranges::end(v));
CHECK(rng[0] == 1);
CHECK(rng[1] == 2);
CHECK(rng[2] == 3);
CHECK(rng[3] == 4);
CHECK(rng(0) == 1);
CHECK(rng(1) == 2);
CHECK(rng(2) == 3);
CHECK(rng(3) == 4);
I personally prefer the ()
operator since it can be easily extended to handle multidimensional ranges but the []
should also be provided for backwards compatibility (and on multidimensional ranges []
could offer one dimensional indexing which is also useful).
If anybody wants to help out with ranges and is capable with gdb, here's your chance. I can't figure out why example/fibonacci.cpp is crashing. It's an infinite recursion problem, but I'm a gdb n00b, and gdb seems to behave unexpectedly when I try to debug it. Any help is GREATLY appreciated.
Hi, I'm using this library in a project, and I encountered this problem. The following code doesn't compile (either on Clang 3.5.0 or gcc 4.9.1; my OS is Arch Linux):
#include <range/v3/numeric/accumulate.hpp>
void foo() {
auto v = std::vector<std::string>{"foo", "bar", "baz"};
auto s = ranges::accumulate(v, std::string{}, [](auto &a, auto const &b) { return a += b; })
}
It compiles if both parameters are by-value or const&, but it doesn't work if one or both is a reference. I can't figure out why it isn't working (maybe something to do with the Accumulateable concept?), but it seems like something that is reasonable to do.
Thanks in advance, and thanks for the library, it's very nice.
I have read your twee and took a look and seen that https://travis-ci.org/ericniebler/range-v3 shows the build failing on a static_assert
.
Notice how @Manu343726 installs gcc-4.9 using apt-get in the .travis.yml and then tests with it:
https://github.com/Manu343726/range-v3/blob/master/.travis.yml
We should be doing that.
The current implementation is extremely inefficient. It's also far too easy to create ranges that infinitely recurse. The fix might be a memo-izing range adapter.
view::ints
returns.. int
s. I just needed an ints
utility for longs
and had to build my own wrapper function object using take
and iota
:
template <class Integral> using irange_t = take_view<iota_view<Integral>>;
template <class Integral>
auto irange(Integral from, Integral to) -> irange_t<Integral> {
return {iota_view<Integral>{from}, detail::iota_minus(to, from) + 1};
}
Is there a better way to do this? (besides adding concept checking?)
Maybe it would be worth it to make ints
more generic and allow the user to specify the integer type, something like:
template<class Integral = int>
struct ints_fn : iota_view<Integral> { ... }
and then letting the function object be a variable template:
template<class Integral = int>
constexpr ints_fn<Integral> ints{};
I don't know if this is possible or there are better alternatives.
Is this intended? If so, what is the rationale?
I just want to write some remarks/questions on the proposal part about D ranges. I am not entirely familiar with actual D ranges itself. I do understand the overall concept, but could be wrong about the details.
D-style ranges can only ever shrink, and they have no notion of position within sequence. If one were to try to implement C++’s iterators on top of D’s ranges, one would immediately run into trouble implementing ForwardIterator’s operator==. As D’s ranges do not represent position, there would be no way to test two ranges to see if their heads referred to the same element. (The front member function that returns the front of a D range is not required to return a reference, nor would that be sufficient to implement a hypothetical hasSameFront function; a repeating range might return the same element multiple times, leading to false positives.)
But wouldn't the D range have a ==
that would satisfy this requirements? Or perhaps have a front_equal
and back_equal
, since a D range can refer to two positions?
On the other hand, two C++ iterators can easily be used to implement a D-style range; thus, every range-based design can be implemented in terms of iterators.
D style ranges can be used to iterate over things like std::tuple
or other sequences that have varying types. These can't be implemented using C++ iterators without losing type information.
The assembly for iterable_strlen
is labeled range_strlen
.
When a class violates a concept, it should be as quick and clear as possible to pin down the root cause of the violation. Is there currently such a way to do it?
Example scenario:
I have a custom class DataFrame
with a custom iterator DataFrameIterator
. I had forgotten to mark operator*
of DataFrameIterator
as const.
I called ranges::for_each
and got the error no matching function for call to object of type ‘const for_each_fn’
.
My lengthy way to find out the root cause (the non-const operator*
) is described below. I describe it just to show that it was quite lengthy for a simple problem. Is there some better current way of going about finding the root cause of such issues? If not, that would be high on the list of making ranges more user friendly for anyone using custom datatypes.
For example, a models_assert<InputIterable>(df)
or even better models_assert<for_each_fn::requirements>(df)
which would give a compile time error with relevant information (as close as possible to the root cause) would be excellent. In concepts.hpp:116 models_
uses some SFINAE and metaprogramming to give true_type if requires_
compiles and it compiles for all recursively refined types. Using similar metaprogramming, but not SFINAE, it should be straight forward (?) to make such a models_assert
. Understanding enough of the metaprogramming framework to do that is a bit outside my current time schedule though :-(.
Is there any ongoing work in this direction?
I started by manually extracting the concept checking pieces of for_each_fn::operator()
:
typename P = ident,
typename I = range_iterator_t<Rng>,
typename V = iterator_common_reference_t<I>,
typename X = concepts::Invokable::result_t<P, V>,
CONCEPT_REQUIRES_(InputIterable<Rng &>() && Invokable<P, V>() && Invokable<F, X>())
Into equivalent usings and asserts at the call sites. It became something like:
using P = ident;
using I = range_iterator_t<Rng>;
using V = iterator_common_reference_t<I>;
using X = concepts::Invokable::result_t<P, V>;
static_assert(InputIterable<Rng &>(),””);
static_assert(Invokable<P, V>(),””);
static_assert(Invokable<F, X>(),””);
Here static_assert(InputIterable<Rng &>(),””);
failed.
I checked the definition of InputIterable
and saw that it refined Iterable
and had a requires_ method which added that concepts::model_of<InputIterator>(begin(t))
.
A static_assert(Iterable <Rng &>(),””);
succeeded and thus the problem narrowed down to that DataFrameIterator
did not satisfy InputIterator
.
I continued in the same fashion.
static_assert(InputIterator<ty>(),””); //fails
//InputIterator refines WeakInputIterator, Iterator and EqualityComparable
static_assert(WeakInputIterator<ty>(),””); //fails
static_assert(Iterator<ty>(),””); //ok
static_assert(EqualityComparable<ty>(),””); //ok
//WeakInputIterator refines WeakIterator and Readable
static_assert(WeakIterator<ty>(),””); //ok
static_assert(Readable<ty>(),””); //fails
//Readable refines SemiRegular
static_assert(SemiRegular<ty>(),””); //ok
Thus one root cause was narrows down to the specifics of Readable
(as coded in its requires_
method). Others might possibly exist in the specifics of InputIterator
and WeakInputIterator
.
Readable::requires_
look like the following (with comments removed):
auto requires_(I i) -> decltype(
concepts::valid_expr(
concepts::model_of<Convertible, reference_t<I>, common_reference_t<I>>(),
concepts::model_of<Convertible, value_t<I> &, common_reference_t<I>>(),
concepts::same_type(indirect_move(i), indirect_move(i, *i))
));
By some additional code navigation I narrowed down a problem to that
DataFrameIterator i; adl_move_detail::indirect_move(i);
wouldn’t compile, again with a “No matching function” error, but that indirect_move(i, *i)
did compile. indirect_move(i)
however only calls indirect_move(i, *i)
. However, it takes i as const ref argument, and I thus tried with
const DataFrameIterator i; indirect_move(i, *i);
I now got the informative answer: Indirection requires pointer operand (‘const I’ (aka ‘const RowIterator<self_t>’) invalid)
, and I could fix the problem to add const to operator*
. However, this had taken embarrassingly long (something like two hours) to find a very simple problem.
Currently, the views are lightweight and non-owning, however the single_view
is an owning view. It seems semantically the current single_view
should be an action. And then add a non-owning single_view
that only accept lvalues, something like this:
template<class T>
struct single_view
{
T* value;
single_view(T& x) : value(&x)
{}
T* begin() { return this->value; }
T* end() { return this->value + 1; }
std::add_const_t<T>* begin() const { return this->value; }
std::add_const_t<T>* end() const { return this->value + 1; }
};
template<class T>
single_view<T> single(T& x)
{
return single_view<T>(x);
}
So then action::single
would capture by value(how it currently does) and view::single
would capture by reference.
One really nice feature would be to be able to sort (or applying any mutating algorithm, really), a zip view
.
Example:
int keys[] = {4,2,1,6};
int values[] = {1,2,3,4};
sort ( view::zip(keys, values) );
AFAIK there is no easy way to do that in C++11, and it does not work with range-v3
atm because sort expects a lvalue-ref to a range.
In general in the current standard the problem of implementing a zip_iterator
with that semantics is that it iterator::reference
must be iterator::value_type&
. Having a zip_iterator
whose value type
is tuple<Ts ... >
and reference
is tuple<Ts& ... >
is (I think) probably the desired semantics.
Even then an overload of swap( tuple<Ts & ...>, tuple <Ts & ...> )
that can swap two tuples of references passed by value would be necessary.
Just random thoughts, apologies if this is has already been discussed.
And this disables the following code :
auto l1 = [](){return 1;};
auto l2 = [](int i){return i==1;};
view::generate(l1) | view::filter(l2) | view::filter(l2);
is this intended behavior?
Indeed, the compile error happens in view::all_fn::from_iterable, and from_iterable member function for range is disabled.
In the implementation of inner product the begin2 iterator is moved when forwarding the range call to the iterator based version:
https://github.com/ericniebler/range-v3/blob/master/include/range/v3/numeric/inner_product.hpp#L108
Why?
I get the following compilation error in the master branch with clang ToT (from two weeks ago, I'll try with ToT and update the issue):
range-v3/include/range/v3/view/counted.hpp:89:39: error: call to non-static member function without an object
argument
RANGES_ASSERT(next(j.base(), n) == i);
^~~~
That is, next (here) tries to call the member function next (here) instead of the intended non-member non-friend next
. Qualifying the call with ::ranges::next
does the trick. A risky guess would be that this doesn't trigger in VS due to missing two-phase look-up.
This is really a clang bug ( http://llvm.org/bugs/show_bug.cgi?id=21605 ), but I also post it here FYI.
This code fails to compile: (tested clang 3.5 & g++ 4.9.1)
#include <range/v3/utility/concepts.hpp>
int main(int argc, char** argv) {
static_assert(ranges::v3::Swappable<int&>(), "");
return 0;
}
In the implementation, concepts::valid_expr
is used, but swap
returns void, which cannot be an arg.
Why is concepts::valid_expr
needed at the first place?
The following code fails to compile when the lambda is mutable, but compiles fine when the 'mutable' keyword is removed:
auto v = std::vector<std::string>{"a", "ab", "abc"};
auto r = ranges::view::transform(v, [](auto const &s) mutable { return s.size(); });
RANGES_FOR(auto const& e, r) {
std::cout << e;
}
This appears to be because semiregular_invokable_ref_t<Fun>
resolves to reference_wrapper<semiregular<invokable_t<Fun>> const>>
. Is this an intended consequence? I can work around it by const_casting inside the lambda, but it would be nice if mutable lambdas could just work. (At least view::filter
seems to have the same issue).
Implement drop_front
versions: view::drop(n)
and view::drop_while(pred)
.
They allow to implement view::drop_back
and view::drop_back_while
by using view::reverse
.
When creating a range algorithm using:
//... alg_fn
RANGES_CONSTEXPR range_algorithm<alg_fn> alg{};
alg({1,2,3,4}, ...); // works
std::initializer_list<int> list;
alg(list, ...); // ambiguous call
The std::initializer_list
overload within range_algorithm
and the operator()
of the algorithm itself are equally good.
This function:
std::unique_ptr<int> data(int i)
{
std::unique_ptr<int> a(new int[i]);
auto rng = ranges::view::counted(a.get(), i);
ranges::iota(rng, 0);
return a;
}
is storing memory allocated with new[]
into std::unique_ptr<int>
, should be std::unique_ptr<int[]>
.
I made a terrible design decision in range_adaptor. Derived classes define custom behaviors by defining a (possibly stateful) adaptor that accepts base cursors and does something to them. The mistake is that the adaptor takes cursors instead of iterators. It is needlessly complex. Redesign.
With as_range
I can obtain a range from a container. There are, however, other things I'd like to get a range from:
It would be nice to have utility functions to easily construct these either as make
functions or as an extension to as_range
. A make
function that returns a range for some of these cases is given here.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.