`std::back()` like function in C++ - c++

I can create begin and end iterators using std::begin() and std::end().
e.g:
int arr[4][4] = <something here>;
auto begin_it = std::begin(arr);
auto end_it = std::end(arr);
However, why do we not have std::front() and std::back(). Is there any specific reason for them to be ommitted?
Are there any similar functions I can use (apart from begin and end of course)?

Not all containers have constant-time access to the last element of the list.
std::forward_list for example.

Just like Marshall Clow said, inconsistent access time across containers should be considered.
My opinion is front would cause UB frequently on empty or not defined front container but begin would not cause that as long as it's not dereferenced.
std::vector v;
auto item = std::front(v); // This line immediately cause undefined behavior.
If std::front exists, it might cause more problems than the convenience it brings.
Because every call of front must come after empty. Then that's two function calls to make it convenient..
std::vector v;
// ...
if( !v.empty() ){
auto item = std::front(v);
// ...tasks
}
HMM.. Is it convenient?
While programmer could get front consciously by *begin(container) and use it before check. All we saved is just an asterisk.
std::vector v;
// ...
if( !v.empty() ){
auto item = *std::begin(v);
// ...tasks
}

Is there any specific reason for them to be ommitted?
Is there any specific reason for them to be included?
Things are not thrown into the standard library just because they can be. The standard library is intended to consist of useful functions, templates, and the like. The "burden of proof" lies with the person who wants something included. It's only after a use-case has been established, presented to the standards committee, and dismissed by said committee that it would be accurate to call the something "omitted".
That being said, there are several potential reasons for something not be included in the standard library, and "not useful" is only one of these. Other potential reasons include "implementation not good enough across all platforms" and "oh, we didn't think of that". While I do not know which reason applies here, I can provide some food for thought by comparing std::end() to a hypothetical std::back().
One can use std::end() with a C-style array (of known size) or anything meeting the requirements of "Container", such as all containers in the standard library. It has great utility in looping over containers, which is a reasonably common operation. A result of adding std::end() to the standard library is that many of the algorithms of the standard library no longer need template specialization to handle C-style arrays. (Admittedly, range-based for loops had a similar effect.)
One would be able to use std::back() with a C-style array (of known size), a std::array, or anything meeting the requirements of "SequenceContainer", such as strings, vectors, deques, lists, and forward lists (and nothing else from the standard library). It has utility in... um... I'm drawing a blank, but I'll grant the possibility of a general use for back(), although probably nowhere close to being as common as looping.
Since std::back() would be applicable in fewer situations than std::end(), it might have been overlooked. At the same time, since std::back() would be applicable in fewer situations than std::end(), it might not meet the "useful" criteria for being included in the standard library.
Are there any similar functions I can use (apart from begin and end of course)?
You could switch from C-style arrays to std::array, then use std::array::back(). After all, std::array is just a C-style array wrapped up to look like a contiguous sequence container. The type declaration is longer, but the functions you are looking for become readily available.
The standard library has a goal of supporting C-style arrays because it is a library, destined to be used by code the library's authors never dreamt of. If you're not writing a library, you probably don't really need to support C-style arrays.

Related

Why c++ constrained algorithms are in the ranges namespace? [duplicate]

Why is std::range::sort (and other range-based algorithms) implemented in the range namespace? Why isn't it defined as an overload of std::sort taking a range?
It's to avoid disrupting existing code bases. Eric Niebler, Sean Parent and Andrew Sutton discussed different approaches in their design paper D4128.
3.3.6 Algorithm Return Types are Changed to Accommodate Sentinels
... In similar fashion, most algorithm get new return types when they
are generalized to support sentinels. This is a source-breaking change
in many cases. In some cases, like for_each, the change is unlikely to
be very disruptive. In other cases it may be more so. Merely accepting
the breakage is clearly not acceptable. We can imagine three ways to
mitigate the problem:
Only change the return type when the types of the iterator and the sentinel differ. This leads to a slightly more complicated interface
that may confuse users. It also greatly complicates generic code,
which would need metaprogramming logic just to use the result of
calling some algorithms. For this reason, this possibility is not
explored here.
Make the new return type of the algorithms implicitly convertible to the old return type. Consider copy, which currently returns the
ending position of the output iterator. When changed to accommodate
sentinels, the return type would be changed to something like pair<I, O>; that is, a pair of the input and output iterators. Instead of
returning a pair, we could return a kind of pair that is implicitly
convertible to its second argument. This avoids breakage in some, but
not all, scenarios. This subterfuge is unlikely to go completely
unnoticed.
Deliver the new standard library in a separate namespace that users must opt into. In that case, no code is broken until the user
explicitly ports their code. The user would have to accommodate the
changed return types then. An automated upgrade tool similar to clang
modernize can greatly help here.
We, the authors, prefer (3).
Ultimately, it was to be the least disruptive to existing code bases that move onto building using C++20 enabled compilers. It's the approach they themselves preferred, and seems like the rest is history.

Do C/C++ have standard 'slice' container?

I often use a slice structure in my projects:
struct SSlice {
void *pData;
size_t length;
};
Also I see other projects use similar containers to work with data w/o copying it (like RocksDB, MDB, etc...). Do anybody knows is there a standard (or OS-related) header with such container?
In STL, linux headers, no matter.
UPD. Main purpose of such container in my and mentioned projects is to work with data w/o copying it. E.g. I use it to parse URI path or LDAP DN and represent it as vector of slices.
It is more typical in C++ standard library, to use a range of iterators (begin, end), rather than an iterator and length (begin, length). Pointers are a case of iterator, which is a more general concept.
There exist no standard structure for ranges, nor slices† that you describe. The standard interfaces treat the begin and end as separate objects.
However, addition of ranges has been proposed and there exists a technical specification, that may already be supported by some standard library implementations.
† At least, not in general, but there is the special std::valarray container which provides a slice interface to its contents.
std::string_view is a C++17 non-owning view of a range of characters with std::string-like functionality. It is intended to speed oarsing, among other things.
span and array_view are names for various standarization and proto-standization efforts that also match your concept, but are not string-presuming.

How to write a function accepting a std::vector or std::list?

Bit of a simple question this one, I guess.
Vectors and lists both have push and pop functions, and - more importantly - can be iterated over:
for ( auto value : items )
...
std::vector and std::list don't seem to share a base class, however. The question is, therefore: How do I write a function that will accept either one (or, indeed, anything else that fits the implementation)?
std::list<int> a;
std::vector<int> b;
DoSomething(a);
DoSomething(b);
I'd like to do it without overloading. If templates are used, they shouldn't cause insane error messages. For example, the following code --
int a;
DoSomething(a);
-- should result in a compile error at the call site, not somewhere inside the template!
Anyone have any ideas?
The C++ standardisation committee tried to introduce concepts to C++0x (now C++11) to resolve the issues you raise here. They were forced to back them out late in the piece, so we'll have to wait until a future version of the standard.
Boost's BCCL offers a portable interim solution. I've never used the library, so I can't vouch for or against it.
Most of the stl algorithms used iterators to as a layer of abstraction from the container.
For example the sort takes 2 random access iterators to sort :
template <class RandomAccessIterator>
void sort (RandomAccessIterator first, RandomAccessIterator last);
Most of the algorithms can be implemented using this idiom
Depending on the algorithm you plan to implement you will need to choose between the 4 types of standard iterators
Here is a link which explains wich type would be better suited

Why isn't std::initializer_list a language built-in?

Why isn't std::initializer_list a core-language built-in?
It seems to me that it's quite an important feature of C++11 and yet it doesn't have its own reserved keyword (or something alike).
Instead, initializer_list it's just a template class from the standard library that has a special, implicit mapping from the new braced-init-list {...} syntax that's handled by the compiler.
At first thought, this solution is quite hacky.
Is this the way new additions to the C++ language will be now implemented: by implicit roles of some template classes and not by the core language?
Please consider these examples:
widget<int> w = {1,2,3}; //this is how we want to use a class
why was a new class chosen:
widget( std::initializer_list<T> init )
instead of using something similar to any of these ideas:
widget( T[] init, int length ) // (1)
widget( T... init ) // (2)
widget( std::vector<T> init ) // (3)
a classic array, you could probably add const here and there
three dots already exist in the language (var-args, now variadic templates), why not re-use the syntax (and make it feel built-in)
just an existing container, could add const and &
All of them are already a part of the language. I only wrote my 3 first ideas, I am sure that there are many other approaches.
There were already examples of "core" language features that returned types defined in the std namespace. typeid returns std::type_info and (stretching a point perhaps) sizeof returns std::size_t.
In the former case, you already need to include a standard header in order to use this so-called "core language" feature.
Now, for initializer lists it happens that no keyword is needed to generate the object, the syntax is context-sensitive curly braces. Aside from that it's the same as type_info. Personally I don't think the absence of a keyword makes it "more hacky". Slightly more surprising, perhaps, but remember that the objective was to allow the same braced-initializer syntax that was already allowed for aggregates.
So yes, you can probably expect more of this design principle in future:
if more occasions arise where it is possible to introduce new features without new keywords then the committee will take them.
if new features require complex types, then those types will be placed in std rather than as builtins.
Hence:
if a new feature requires a complex type and can be introduced without new keywords then you'll get what you have here, which is "core language" syntax with no new keywords and that uses library types from std.
What it comes down to, I think, is that there is no absolute division in C++ between the "core language" and the standard libraries. They're different chapters in the standard but each references the other, and it has always been so.
There is another approach in C++11, which is that lambdas introduce objects that have anonymous types generated by the compiler. Because they have no names they aren't in a namespace at all, certainly not in std. That's not a suitable approach for initializer lists, though, because you use the type name when you write the constructor that accepts one.
The C++ Standard Committee seems to prefer not to add new keywords, probably because that increases the risk of breaking existing code (legacy code could use that keyword as the name of a variable, a class, or whatever else).
Moreover, it seems to me that defining std::initializer_list as a templated container is quite an elegant choice: if it was a keyword, how would you access its underlying type? How would you iterate through it? You would need a bunch of new operators as well, and that would just force you to remember more names and more keywords to do the same things you can do with standard containers.
Treating an std::initializer_list as any other container gives you the opportunity of writing generic code that works with any of those things.
UPDATE:
Then why introduce a new type, instead of using some combination of existing? (from the comments)
To begin with, all others containers have methods for adding, removing, and emplacing elements, which are not desirable for a compiler-generated collection. The only exception is std::array<>, which wraps a fixed-size C-style array and would therefore remain the only reasonable candidate.
However, as Nicol Bolas correctly points out in the comments, another, fundamental difference between std::initializer_list and all other standard containers (including std::array<>) is that the latter ones have value semantics, while std::initializer_list has reference semantics. Copying an std::initializer_list, for instance, won't cause a copy of the elements it contains.
Moreover (once again, courtesy of Nicol Bolas), having a special container for brace-initialization lists allows overloading on the way the user is performing initialization.
This is nothing new. For example, for (i : some_container) relies on existence of specific methods or standalone functions in some_container class. C# even relies even more on its .NET libraries. Actually, I think, that this is quite an elegant solution, because you can make your classes compatible with some language structures without complicating language specification.
This is indeed nothing new and how many have pointed out, this practice was there in C++ and is there, say, in C#.
Andrei Alexandrescu has mentioned a good point about this though: You may think of it as a part of imaginary "core" namespace, then it'll make more sense.
So, it's actually something like: core::initializer_list, core::size_t, core::begin(), core::end() and so on. This is just an unfortunate coincidence that std namespace has some core language constructs inside it.
Not only can it work completely in the standard library. Inclusion into the standard library does not mean that the compiler can not play clever tricks.
While it may not be able to in all cases, it may very well say: this type is well known, or a simple type, lets ignore the initializer_list and just have a memory image of what the initialized value should be.
In other words int i {5}; can be equivalent to int i(5); or int i=5; or even intwrapper iw {5}; Where intwrapper is a simple wrapper class over an int with a trivial constructor taking an initializer_list
It's not part of the core language because it can be implemented entirely in the library, just line operator new and operator delete. What advantage would there be in making compilers more complicated to build it in?

Why aren't there convenience functions for set_union, etc, which take container types instead of iterators?

std::set_union and its kin take two pairs of iterators for the sets to be operated on. That's great in that it's the most flexible thing to do. However they very easily could have made an additional convenience functions which would be more elegant for 80% of typical uses.
For instance:
template<typename ContainerType, typename OutputIterator>
OutputIterator set_union( const ContainerType & container1,
const ContainerType & container2,
OutputIterator & result )
{
return std::set_union( container1.begin(), container1.end(),
container2.begin(), container2.end(),
result );
}
would turn:
std::set_union( mathStudents.begin(), mathStudents.end(),
physicsStudents.begin(), physicsStudents.end(),
students.begin() );
into:
std::set_union( mathStudents, physicsStudents, students.begin() );
So:
Are there convenience functions like this hiding somewhere that I just haven't found?
If not, can anyone thing of a reason why it would be left out of STL?
Is there perhaps a more full featured set library in boost? (I can't find one)
I can of course always put my implementations in a utility library somewhere, but it's hard to keep such things organized so that they're used across all projects, but not conglomerated improperly.
Are there convenience functions like this hiding somewhere that I just haven't found?
Not in the standard library.
If not, can anyone thing of a reason why it would be left out of STL?
The general idea with algorithms is that they work with iterators, not containers. Containers can be modified, altered, and poked at; iterators cannot. Therefore, you know that, after executing an algorithm, it has not altered the container itself, only potentially the container's contents.
Is there perhaps a more full featured set library in boost?
Boost.Range does this. Granted, Boost.Range does more than this. It's algorithms don't take "containers"; they take iterator ranges, which STL containers happen to satisfy the conditions for. They also have lazy evaluation, which can be nice for performance.
One reason for working with iterators is of course that it is more general and works on ranges that are not containers, or just a part of a container.
Another reason is that the signatures would be mixed up. Many algorithms, like std::sort have more than one signature already:
sort(Begin, End);
sort(Begin, End, Compare);
Where the second one is for using a custom Compare when sorting on other than standard less-than.
If we now add a set of sort for containers, we get these new functions
sort(Container);
sort(Container, Compare);
Now we have the two signatures sort(Begin, End) and sort(Container, Compare) which both take two template parameters, and the compiler will have problems resolving the call.
If we change the name of one of the functions to resolve this (sort_range, sort_container?) it will not be as convenient anymore.
I agree, STL should take containers instead of iterators-pairs for the following reasons;
Simpler code
Algorithms could be overloaded for specified containers, ie, could use the map::find algorithm instead of std::find -> More general code
A subrange could easily be wrapped into a container, as is done in boost::range
#Bo Persson has pointed to a problem with ambiguity, and I think that's quite valid.
I think there's a historical reason that probably prevented that from ever really even being considered though.
The STL was introduced into C++ relatively late in the standardization process. Shortly after it was accepted, the committee voted against even considering any more new features for addition into C++98 (maybe even at the same meeting). By the time most people had wrapped their head around the existing STL to the point of recognizing how much convenience you could get from something like ranges instead of individual iterators, it was too late to even be considered.
Even if the committee was still considering new features, and somebody had written a proposals to allow passing containers instead of discrete iterators, and had dealt acceptably with the potential for ambiguity, I suspect the proposal would have been rejected. Many (especially the C-oriented people) saw the STL as a huge addition to the standard library anyway. I'm reasonably certain quite a few people would have considered it completely unacceptable to add (lots) more functions/overloads/specializations just to allowing passing one parameter in place of two.
Using the begin & end elements for iteration allows one to use non-container types as inputs. For example:
ContainerType students[10];
vector<ContainerType> physicsStudents;
std::set_union(physicsStudents.begin(), physicsStudents.end(),
&students[0], &students[10],
physicsStudents.begin());
Since they are such simple implementations, I think it makes sense not to add them to the std library and allow authors to add their own. Especially given that they are templates, thus potentially increasing the lib size of the code and adding convenience functions across std would lead to code bloat.