C++17 – What’s New in the Library?
What’s new in the library? A lot. To make the long story short. We get a std::string_view, parallel algorithm of the Standard Template Library, a file system library, and the three new data types std::any, std::optional, and std::variant. Let’s look at the details.
Our journey starts with std::string_view.
std::string_view
A std::string_view is a non-owning reference to a string. It represents a view of a sequence of characters. This sequence of characters can be a C++ string or a C-string. In a typical way, C++17 offers four type synonyms for the underlying character types.
std::string_view std::basic_string_view<char> std::wstring_view std::basic_string_view<wchar_t> std::u16string_view std::basic_string_view<char16_t> std::u32string_view std::basic_string_view<char32_t>
The question remains. Why do we need a std::string_view? Why had Google, LLVM, and Bloomberg already an implementation of a string view? The answer is easy. It’s pretty cheap to copy a std::string_view. A std::string_view only needs two pieces of information: the pointer to the character sequence and their length. As you may assume, the std::string_view and its three siblings consist mainly of reading operations that follow the interface of std::string. Mainly because it gets the new methods remove_prefix and remove_suffix.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
// string_view.cpp #include <iostream> #include <string> #include <experimental/string_view> int main(){ std::string str = " A lot of space"; std::experimental::string_view strView = str; strView.remove_prefix(std::min(strView.find_first_not_of(" "), strView.size())); std::cout << "str : " << str << std::endl << "strView : " << strView << std::endl; std::cout << std::endl; char arr[] = {'A',' ','l','o','t',' ','o','f',' ','s','p','a','c','e','\0', '\0', '\0'}; std::experimental::string_view strView2(arr, sizeof arr); auto trimPos = strView2.find('\0'); if(trimPos != strView2.npos) strView2.remove_suffix(strView2.size() - trimPos); std::cout << "arr : " << arr << ", size=" << sizeof arr << std::endl << "strView2: " << strView2 << ", size=" << strView2.size() << std::endl; } |
The program should not surprise you. The std::string_view‘s in lines 10 and 18 get their C++-string and character-array reference. In line 11, all leading non-spaces (strView.find_first_not_of(” “)) are removed, and in line 20, all trailing “\0”-characters (strView2.find(‘\0″)) are removed. By using the namespace experimental, I can already execute the program at cppreference.com.
Modernes C++ Mentoring
Do you want to stay informed: Subscribe.
Now, to something more familiar.
Parallel algorithm of the Standard Template Library
My story is relatively short. 69 Standard Template Library algorithms (STL) algorithms will be available in sequential, parallel, parallel, and vectorized version. Additionally, we get eight new algorithms. Look at the 69 new variants (black) and the 8 (red) new algorithms.
That was all. I already wrote a post Parallel Algorithm of the Standard Template Library. On the contrary, the filesystem library should be new to you.
The filesystem library
The new filesystem library is based on boost::filesystem. Some of its components are optional. That means not all functionality of std::filesytem is available on each implementation of the filesystem library. For example, FAT-32 does not support symbolic links.
The library uses three concepts file, file name, and path. Files can be directories, hard links, symbolic links, or regular files. Paths can be absolute or relative.
There is a powerful interface for reading and manipulating the filesystem. Use cppreference.com for the details. Here is a first impression.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
// filesystem.cpp #include <fstream> #include <iostream> #include <string> #include <experimental/filesystem> namespace fs = std::experimental::filesystem; int main(){ std::cout << "Current path: " << fs::current_path() << std::endl; std::string dir= "sandbox/a/b"; fs::create_directories(dir); std::ofstream("sandbox/file1.txt"); fs::path symPath= fs::current_path() /= "sandbox"; symPath /= "syma"; fs::create_symlink("a", "symPath"); std::cout << "fs::is_directory(dir): " << fs::is_directory(dir) << std::endl; std::cout << "fs::exists(symPath): " << fs::exists(symPath) << std::endl; std::cout << "fs::symlink(symPath): " << fs::is_symlink(symPath) << std::endl; for(auto& p: fs::recursive_directory_iterator("sandbox")) std::cout << p << std::endl; // fs::remove_all("sandbox"); } |
fs::current_path() in line 11 returns the current path. You can create a directory hierarchy (line 14) with std::filesystem. Line 18 looks a little bit odd. The /= is overloaded for a path. Therefore, I can directly create a symbolic link in line 19. You can check the properties of a file (lines 21 – 23). The call recursive_directory_iterator in line 26 is quite powerful. You can use it to traverse directories recursively. Of course, I can not remove a directory (line 28) on an online compiler.
Here is the output of the program.
What has the new data type std::any, std::optional, and std::variant in common? They are based on boost.
std::any
std::any will be the right choice if you want a container with an arbitrary type. The arbitrary type is not a hundred percent correct. std::any requires, that its values must be copyable. Here is a short example.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// any.cpp #include <iostream> #include <string> #include <vector> #include <any> struct MyClass{}; int main(){ std::cout << std::boolalpha; std::vector<std::any> anyVec(true,2017,std::string("test"),3.14,MyClass()); std::cout << "std::any_cast<bool>anyVec[0]: " << std::any_cast<bool>(anyVec[0]); // true int myInt= std::any_cast<int>(anyVec[1]); std::cout << "myInt: " << myInt << std::endl; // 2017 std::cout << std::endl; std::cout << "anyVec[0].type().name(): " << anyVec[0].type().name(); // b std::cout << "anyVec[1].type().name(): " << anyVec[1].type().name(); // i } |
The output of the program is in the source code. Line 14 defines a std::vector<std::any>. To get one of its elements, you have to use std::any_cast. If you use the wrong type, you will get a std::bad_any_cast exception. For further details, go to cppreferenc.com or wait for my additional post.
std::any can have values of arbitrary types, std::optional can have a value or no value.
std::optional
I will make it relatively short. In the post Monads in C++, I already wrote about the monad std::optional.
The third new data type from boost is std::variant.
std::variant
A std::variant is a type-safe union. An instance of std::variant has a value from one of its types. The type must not be a reference, array, or void. A union can have one type more than once. A default-initialized std::variant will be initialized with its first type. In this case, the first type must have a default constructor. Here is an example based on cppreference.com.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// variant.cpp #include <variant> #include <string> int main(){ std::variant<int, float> v, w; v = 12; // v contains int int i = std::get<int>(v); w = std::get<int>(v); w = std::get<0>(v); // same effect as the previous line w = v; // same effect as the previous line // std::get<double>(v); // error: no double in [int, float] // std::get<3>(v); // error: valid index values are 0 and 1 try{ std::get<float>(w); // w contains int, not float: will throw } catch (std::bad_variant_access&) {} std::variant<std::string> v("abc"); // converting constructors work when unambiguous v = "def"; // converting assignment also works when unambiguous } |
I define in line 8 both variants v and w. Both can have an int and a float value. Their value is 0. v becomes 12 on line 9. std::get<int>(v) returns the value. In lines 11-13, you see three possibilities to assign variant v the variant w. But you have to keep a few rules in mind. You can ask for the value of a variant by type (line 15) or index (line 16). The type must be unique and the index valid. On line 19, the variant w holds an int value. Therefore, I get a std::bad_variant_access exception in line 21. A conversion can occur if the constructor call or assignment call is unambiguous. That is why it’s possible to construct a std::variant<std::string> in line 23 with a C-string or assign a new C-string to the variant (line 24).
What’s next?
I stick with the C++17 standard. After I gave in this and the last post an overview of the core language and the library, I will dive into the next post into the details (Proofreader Marc Bertola).
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Stephen Kelley, Kyle Dean, Tusar Palauri, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, Philipp Lenk, Charles-Jianye Chen, Keith Jeffery,and Matt Godbolt.
Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.
My special thanks to Embarcadero | |
My special thanks to PVS-Studio | |
My special thanks to Tipi.build | |
My special thanks to Take Up Code | |
My special thanks to SHAVEDYAKS |
Seminars
I’m happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.
Standard Seminars (English/German)
Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.
- C++ – The Core Language
- C++ – The Standard Library
- C++ – Compact
- C++11 and C++14
- Concurrency with Modern C++
- Design Pattern and Architectural Pattern with C++
- Embedded Programming with Modern C++
- Generic Programming (Templates) with C++
- Clean Code with Modern C++
- C++20
Contact Me
- Mobil: +49 176 5506 5086
- Mail: schulung@ModernesCpp.de
- German Seminar Page: www.ModernesCpp.de
- Mentoring Page: www.ModernesCpp.org
Modernes C++ Mentoring,
Leave a Reply
Want to join the discussion?Feel free to contribute!