6

Why can't calls to STL functions be more brief? I was looking at the following code snippet on cppreference.com:

#include <string>
#include <cctype>
#include <algorithm>
#include <iostream>

int main()
{
    std::string s("hello");
    std::transform(s.begin(), s.end(), s.begin(),
                   [](unsigned char c) { return std::toupper(c); });
    std::cout << s;
}

It seems to me that it should be possible to make this call more brief. The first obvious thing would be to do away with the lambda:

std::string s("hello");
std::transform(s.begin(), s.end(), s.begin(), std::toupper);
std::cout << s;

But this doesn't work. Since you usually want to convert a whole container it should be possible to just use that as a parameter:

std::string s("hello");
std::transform(s, s.begin(), std::toupper);
std::cout << s;

You could also omit the output iterator to return the result by value:

std::string s("hello");
std::cout << std::transform(s, std::toupper);

At this point the temporary variable is unnecessary:

std::cout << std::transform("hello"s, std::toupper);

With added readability:

using namespace std;
cout << transform("hello"s, toupper);

Wouldn't this be more readable and just nicer? Why weren't STL functions designed to allow writing brief code like this? Will it be possible to shorten these calls in a future version of the C++ standard?

Szabolcs
  • 832
  • 11
  • 15
  • 4
    For your last two examples `"hello"` has the type `const char[N]` which means it is not modifiable. – NathanOliver Sep 29 '16 at 11:52
  • 3
    For starters, you cannot just use `std::toupper` on `char`s because of stuff from its C past. [Details](https://stackoverflow.com/questions/21805674/do-i-need-to-cast-to-unsigned-char-before-calling-toupper). – Baum mit Augen Sep 29 '16 at 11:53
  • 2
    while shortening things and removing the "end" iterator etc. You maybe make it less verbose for most cases but you "remove" the cases where it is not like this. C++ can be really flexible and elegant because you give operations a start and end iterator. – Hayt Sep 29 '16 at 11:54
  • 2
    For the verbose syntax, the committee is working on that. Feel free to contribute proposals. – Baum mit Augen Sep 29 '16 at 11:55
  • 2
    Ranges should help. I believe it is a TS now. Otherwise range-v3 is a good option. – NathanOliver Sep 29 '16 at 11:56
  • 1
    Look at [range-v3](https://ericniebler.github.io/range-v3/). – Jarod42 Sep 29 '16 at 12:32
  • 1
    @NathanOliver it just should be `"hello"s` there. Question is still legit. – Slava Sep 29 '16 at 12:45
  • @Baum mit Augen Can you share any details what's being worked on? I'd be interested to know! – Szabolcs Sep 29 '16 at 13:05
  • @NathanOliver In the last 2 examples the transform function would return the result by value and not modify the source. – Szabolcs Sep 29 '16 at 13:16
  • 1
    @Xoralunga The ranges stuff aside they have not gotten very far. They did reserve all namespaces `std[anynumber]` for future use and expressed the desire to get something done. We'll see in 2020 or later. If you feel like contributing, look for the relevant mailing lists and at isocpp.org – Baum mit Augen Sep 29 '16 at 13:18
  • @BaummitAugen You're right. I've removed the comment. – Kuba hasn't forgotten Monica Sep 30 '16 at 16:19

2 Answers2

7

Unfortunately, std::toupper has overloads, so the lambda is the workaround.

Then, with range-v3, you can simplify it to:

auto to_upper = [](unsigned char c) { return std::toupper(c); }; // To handle overloads
std::cout << std::string("Hello world" | ranges::view::transform(to_upper))
          << std::endl;

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
1
std::transform(s.begin(), s.end(), s.begin(),
               [](unsigned char c) { return std::toupper(c); });

The general form just works. Always!

You can use it to transform in-place or to a separate result:
std::transform(s.begin(), s.end(), result.begin(),....

It can transform the whole container, or just a part. Any part of your choice:
std::transform(s.begin() + i, s.begin() + j, s.begin() + i,...

And it works on any sequence, even if the elements are not part of a container.

So the general form would be needed anyway, as it is the most useful one.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • 4
    I understand the need for the general form. I'm interested in knowing why there aren't other forms at least. – Szabolcs Sep 29 '16 at 12:56