If you are part of the Almost Always Auto group, then UDL is very important. He allows you to do this:
auto str = "Foo"s;
So str will be genuine std::string , not const char* . Therefore, it allows you to decide when to do it.
This is also important for outputting an automatic return type:
[]() {return "Foo"s;}
Or any form of type inference, indeed:
template<typename T> void foo(T &&t) {...} foo("Foo"s);
The only advantage that I see when using [...] instead of [...] is that in the first case, the compiler can execute copy-elision (I think), which will be faster than calling the constructor in the second case.
Copying is no faster than calling a constructor. In any case, you call one of the object constructors. The question is which one:
std::string str = "foo";
This will invoke the constructor std::string , which takes const char* . But since std::string should copy the string to its own storage, it should get the length of the string for this. And since he does not know the length, this constructor is forced to use strlen to get it (technically, char_traits<char>::length , but this probably will not be much faster).
In contrast to this:
std::string str = "foo"s;
This will use the UDL template that has this prototype:
string operator "" s(const char* str, size_t len);
See, the compiler knows the length of the string literal. Thus, the UDL code is passed by a pointer to a string and size. Thus, it can call the constructor std::string , which takes const char* and a size_t . Therefore, there is no need to calculate the length of the string.
The advice in question is not for you to get around and convert each use of the literal to version s . If everything is fine with the limitations of the char s array, use it. The advice is that if you are going to store this literal in std::string , it is best to do this while it is still literal and not foggy const char* .