Hello, and welcome to C++ Weekly. I'm your host, Jason Turner, available for
code reviews and on-site training.
In this episode we want to answer the age-old question of how to split a string in C++.
I love my Flexispot Kana Pro Bamboo standing desk, so of course I said yes when the folks
at Flexispot asked me if I wanted to do another sponsorship spot. This time I got the Flexispot
Pro Plus Standing Desk (E7) with mahogany top and black legs. The Pro Plus E7 was easy to set up,
very similar to the setup process for the Kana Pro. The E7 is very stable,
comes in a wide range of widths, is nearly silent during use and is less expensive than their
competitors. The premium keypad is easy to use and program with four different presets available,
and I'll just say from personal experience using this - it is very accurate and gets you back
to the height that you last had it set to. Be sure to check out my exclusive referral link
for a discount on your first purchase. Also be sure to join the Flexispot Tech Day
during September 7th through the 9th, 2022 for up to $200 off your purchase.
Make sure you don't miss out otherwise you'll have to wait for Black Friday to see such great deals
again. So before we continue I want to remind you again that episode ideas are driven by you on C++
Weekly, so be sure to go to the Github (page). Propose video ideas, up-vote, down-vote,
whatever you would like to see here; and also be sure to check out the video description
for links to my C++ puzzle books and my C++ Best Practices book. Okay, so this is a question that
has been asked for a very long time. If we look on stack overflow this is 13 years ago and 5 months,
and the most up-voted answers seem, shall we say, less than simple. If you look through this you've
got boost, string algorithm, string splitting questions using stringstream as an option,
which is less than ideal also; and oh, you know, it just isn't a pretty picture. Now
on CppCast a long time ago someone pointed out to me that C++20 Ranges actually solves
this problem today. Okay. Let's start with this simple boilerplate project; I'm using GCC trunk.
This does require C++20 ranges like I said, and well, I mean, yes, it is most of the way
through 2022 right now, but uh, well, compilers are still catching up on this whole ranges in
C++20 thing in some cases here; but we're talking about the ranges that come with the standard
library, not ranges V3. (You're welcome to check that out as well.) So I can in C++20 do this,
and well that works at least in theory. Um, I'm getting a compile time error because I
set a value that I am not using, and well, that's true. I set the split_strings.
So it is important to know first of all that this is lazy evaluated,
and now the second thing that you need to know is that we've just been given a range of ranges
and so if I want to output these things I might do something like this,
which works. We are actually able with fmt::print to output these ranges of ranges.
It works quite well in fact. We get "Hello World C++20!" printed exactly as we wanted it to.
Now that assumes that you have lib {fmt} available to you.
If I wanted to do this, then I get a "no match for" these two things here, and this is a
"const, ranges, subrange, blah, blah, blah, blah, blah," like it's it's a large type.
So I can do this - I can manually construct a string view from the beginning to the end,
and then the other question that we have to ask is, well, we've seen lib {fmt} but what about
format that's included with our standard library? Unfortunately I can't really show you that right
now because we don't have format included with our standard library yet from GCC, but that's okay.
Let's go ahead and take a quick look at how this will get slightly better in C++23. We have an
overload for string view construction where I can pass in this subrange and I will get a string_view
nice and helpfully out of it, and we can access that. That's awesome. This is so much better
than doing something as simple as a string split used to be, and the code that's being generated is
really, honestly, not so bad. Let's go ahead and get the iostream cruft out of the way,
and uh, it's actually a very small binary that's been generated for us here. It's amazing really.
Everything in the ranges library is 'constexpr' capable so I can do that,
but this is actually going to cause a different compile time error and it comes down
to this - since it's lazy evaluation it needs to be mutated to actually do the execution here.
So I don't currently think that there would be any advantage to creating, like, a static 'constexpr'
lazy evaluated view of a thing. Maybe if it's a very complicated view, but I don't think so.
Part of the problem is that you do have to make a copy of the thing. Now granted with C++23's 'auto'
capability we can make this copy explicitly here and give it a copy that it can then mutate,
but I don't think we've gained anything; but we can... I'm not going to actually dig into
a specific use case here, but let's just say, um, it's possible that compile time scripting,
parsing, of things could be possible because we can use these things inside
of constexpr functions. We can create and use views inside of constexpr functions,
but not static contexpr values inside of a constexpr function. Anyhow, that just proves
that we can use views in a constexpr function, and yeah, there we go, finally a simple string split
capability in C++20. A little bit more usable in C++23, and you have to be aware of the fact that
you're getting a subrange back, so you have to do something intelligent with that; but thank you for
watching this episode of C++ Weekly. Uh, be sure to subscribe, and you know, a "like" always helps.