It is fully safe to change boost::array to std::array? Can it cause any discrepancies?
Is boost::array better over std::array (performance?)?
std::array<T,N> and boost::array<T,N> are standard layout aggregates containing nothing but an array of T[N].
Their interaction with namespace boost and namespace std may be different (Specifically, ADL will find std functions for std::array, and boost functions for boost::array).
So, if there is a function foo in boost, calling foo(some_array) might work if some_array was from boost, and not if it was from std.
The only container algorithms currently in std are std::begin and std::end (and similar the new ones size empty etc if you include near-future ones). Ranges v3 (or whatever gets published) might add some more.
There are more container algorithms in boost than in std. Some of them might fail to build.
In the worst case, someone could write a function with the same name as a container algorithm in boost, with an argument that can implicitly convert from std::array, and the unqualified call to that function could result in a conversion after you change the variable type, while before it called the boost container algorithm.
Similarly, someone could write code that explicitly checks if a template argument is a boost::array and behave differently if it is.
Both of those are a bit of a stretch.
Finally, std::array has modern noexcept decoration, and boost has a public c_array member you can get at (the name std::array member variables is, I believe, not specified). (via #Potatoswatter). I'd personally expect std::array to have better support going forward, as boost::array mainly existed because std lacked the functionality.
Other than those corner cases, std::array should be a drop-in replacement.
Related
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.
I have been writing in c++ for a few months, and i am comfortable enough with it now to begin implementing my own library, consisting of things that i have found myself reusing again and again. One thing that nagged me was the fact that you always had to provide a beginning and end iterator for functions like std::accumulate,std::fill etc...
The option to provide a qualified container was completely absent and it was simply an annoyance to write begin and end over and over. So, I decided to add this functionality to my library, but i came across problem, i couldn't figure out the best approach of doing so. Here were my general solutions:
1. Macros
- A macro that encapsulates an entire function call
ex. QUICK_STL(FCall)
- A macro that takes the container, function name, and optional args
ex. QUICK_STL(C,F,Args...)
2. Wrapper Function/Functor
- A class that takes the container, function name, and optional args
ex. quick_stl(F, C, Args...)
3. Overload Functions
- Overload every function in namespace std OR my library namespace
ex
namespace std { // or my library root namespace 'cherry'
template <typename C, typename T>
decltype(auto) count(const C& container, const T& value);
}
I usually steer clear of macros, but in this case it could certainty save alot
of lines of code from being written. With regards to function overloading, every single function that i want to use i must overload, which wouldn't really scale. The upside to that approach though is that you retain the names of the functions. With perfect forwarding and decltype(auto) overloading becomes alot easier, but still will take time to implement, and would have to be modified if ever another function was added. As to whether or not i should overload the std namespace i am rather skeptical on whether or not it would be appropriate in this case.
What would be the most appropriate way of going about overloading functions in the STD namespace (note these functions will only serve as proxy's to the original functions)?
You need to read this: Why do all functions take only ranges, not containers?
And This: STL algorithms: Why no additional interface for containers (additional to iterator pairs)?
I have been writing in c++ for a few months, and i am comfortable
enough with it now to begin implementing my own library...
Let me look on the brighter side and just say... Some of us have been there before.... :-)
One thing that nagged me was the fact that you always had to provide a
beginning and end iterator for functions like
std::accumulate,std::fill etc...
That's why you have Boost.Ranges and the Eric's proposed ranges that seems like it isn't gonna make it to C++17.
Macros
See Macros
Wrapper Function/Functor
Not too bad...Provided you do it correctly, You can do that, that's what essentially Ranges do for Containers... See the aforementioned implementations
Overload Functions
Overload every function in namespace std ...
Don't do that... The C++ standard doesn't like it.
See what the standard has to say
$17.6.4.2.1 The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within
namespace std unless otherwise specified. A program may add a template
specialization for any standard library template to namespace std only
if the declaration depends on a user-defined type and the
specialization meets the standard library requirements for the
original template and is not explicitly prohibited.
I asked a question on Iterators here: Prefer Iterators Over Pointers? I've come to understand some of the protection and debug capabilities they offer as a result.
However, I believe that begin and end now offer similar possibilities on C-style array.
If I want to create a const string that will only be iterated over in STL algorithms, is there still an advantage to using a const string, or should I prefer const char[] with begin and end?
So the answer depends on what version of c++ you're using
C++98
Because C++98 doesn't have std::begin or std::end the best move is just to accept you're going to have to pay the costs of construction and use std::string. If you have boost available you should still consider boost::string_ref for two reasons. First its construction will always avoid allocation, and is overall much simpler than std::string.
boost::string_ref works because it only stores a pointer to the string and the length. Thus the overhead is minimal in all cases.
c++11
Very similar to C++98 except the recommendation to use boost::string_ref becomes MUCH stronger because c++11 has constexpr which allows the compiler to bypass construction completely by constructing the object at compile time.
c++1z
Allegedly (it's not final) the Library Fundamentals TS will be bringing us std::string_view. boost::string_ref was a prototype for an earlier proposal of std::string_view and is designed to bring the functionality to all versions of C++ in some form.
On C++14 String Literals
C++14 introduced string literals with the syntax "foo"s unfortunately this is just a convenience. Because operator""s is not constexpr it cannot be evaluated at compile time and thus does not avoid the penalty that construction brings. So it can be used to make code nicer looking, but it doesn't provide any other benefit in this case.
Since there are now generic iterator on c++ standard library like std::begin() and std::end(), I am wondering why there is no std::clear() method to clear a container?
The nice thing about std::begin/end is that it can be implemented for arrays. However it can only be implemented as namespace scope functions for arrays. Therefore in generic code it is nice to have std::begin/end so that the generic code doesn't have to decide whether it needs to use namespace scope or member functions when needing begin/end.
But I know of no such analogy for std::clear. It can only be implemented for containers which have member clear(). There is no dilemma for how to use it in generic code (at least not that I can think of).
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?