220 36884 <5c51d89a-54b6-490b-87f2-09ed263d8322@isocpp.org> article
Path: news.gmane.org!.POSTED!not-for-mail
From: Nicol Bolas <jmckesson@gmail.com>
Newsgroups: gmane.comp.lang.c++.isocpp.proposals
Subject: Re: String interpolation
Date: Mon, 12 Feb 2018 07:45:41 -0800 (PST)
Lines: 552
Approved: news@gmane.org
Message-ID: <5c51d89a-54b6-490b-87f2-09ed263d8322@isocpp.org>
References: <356d5835-f1bf-4699-94f5-0b2d3d0b9c0e@isocpp.org>
 <CAMD6iD9aT26x8GQHnQL+kuj3Rq8fVQSfYYFtvTnFidkf6jU_ag@mail.gmail.com>
 <25CCF885-86AD-4D51-8F5C-C46376D34DE0@gmail.com> <4890431.TR9UepuQra@tjmaciei-mobl1>
 <CALvx3hac77b6Z=EOWzKqynALi1-352OvY0dnnOer8rN6tfa01g@mail.gmail.com> <1cdb6300-7397-46d7-bce9-62e6e8dac40b@isocpp.org>
 <CAC+0CCOSZHaTA=YPSDU8Add7mE_BYcYPRCmGW8TRPtZhdqL8Hw@mail.gmail.com>
 <4bce681e-e729-4124-9322-69291fdb6678@isocpp.org>
 <f5feb9a0-99d3-433a-ae46-af34c8d00a61@isocpp.org>
 <8e456af5-09c3-461d-8562-30df127e93af@isocpp.org>
 <bd24b702-025a-4b06-976b-559c779851e1@isocpp.org>
 <f63ed807-c5f6-4997-b03f-b4bc16a70982@isocpp.org>
 <28e80709-5ebb-44d2-b26d-22cafd681330@isocpp.org>
 <52b86f0a-b3b9-455f-9d4d-0f6b15192c90@isocpp.org>
 <1e9a5468-6efa-48a2-87ce-6bdb6d5c4e83@isocpp.org>
 <750ecf62-9637-40f4-8585-e3be2780fb46@isocpp.org>
 <f8f4407b-ecf6-4a4a-b3f6-c65813e3f843@isocpp.org>
 <5b5435db-772e-4c38-8867-f6fbc66d7cec@isocpp.org>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: blaine.gmane.org
Mime-Version: 1.0
Content-Type: multipart/mixed; 
	boundary="----=_Part_9609_446297566.1518450341499"
X-Trace: blaine.gmane.org 1518450249 12363 195.159.176.226 (12 Feb 2018 15:44:09 GMT)
X-Complaints-To: usenet@blaine.gmane.org
NNTP-Posting-Date: Mon, 12 Feb 2018 15:44:09 +0000 (UTC)
Cc: florian.csdt@gmail.com
To: ISO C++ Standard - Future Proposals <std-proposals@isocpp.org>
Original-X-From: std-proposals+bncBCEKFTV6ZUMBBJXNQ3KAKGQEMXDIA2Y@isocpp.org Mon Feb 12 16:44:05 2018
Return-path: <std-proposals+bncBCEKFTV6ZUMBBJXNQ3KAKGQEMXDIA2Y@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-vk0-f69.google.com ([209.85.213.69])
	by blaine.gmane.org with esmtp (Exim 4.84_2)
	(envelope-from <std-proposals+bncBCEKFTV6ZUMBBJXNQ3KAKGQEMXDIA2Y@isocpp.org>)
	id 1elGGY-0001Ch-7I
	for gclcip-std-proposals@m.gmane.org; Mon, 12 Feb 2018 16:43:38 +0100
Original-Received: by mail-vk0-f69.google.com with SMTP id m190sf9312545vkg.5
        for <gclcip-std-proposals@m.gmane.org>; Mon, 12 Feb 2018 07:45:44 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=isocpp-org.20150623.gappssmtp.com; s=20150623;
        h=date:from:to:cc:message-id:in-reply-to:references:subject
         :mime-version:x-original-sender:reply-to:precedence:mailing-list
         :list-id:list-post:list-help:list-archive:list-subscribe
         :list-unsubscribe;
        bh=OIDaDeh+Y8bPq0zRaBd5gZuzKnEu/HyEAMyXwiNi4iM=;
        b=Y5It1/Bllnh3U2g6yKieUHfvK+uy48JNVLdnSpODpq0loGbKrPNkt5ywcbP6ckeo/9
         d5W9yr7NlYN8/uWeNlElZBIqgHHZXMZBxey+DJ7s9NLtxoS6hMIv+0ucgIUfDn5BHTRc
         rpXyDh9AljH+vtUYl08KKytDPmPmq9KWhlPqIcWCM3el804/boMdu02i0L4UAyqi+jI7
         58FKkR+eOEtWiwHm6lX5gdYew1i1rH7n0cuu+wztuVoj4nuGd8yskn3BqkwurFWlGZoT
         oXQ/K/+24KMWqtNIPhz4Sp96yT+2ipiXJa+7IArgLv904JCD+Q9JQ6ADZ89JTbxBUJZe
         NdWQ==
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=20161025;
        h=date:from:to:cc:message-id:in-reply-to:references:subject
         :mime-version:x-original-sender:reply-to:precedence:mailing-list
         :list-id:list-post:list-help:list-archive:list-subscribe
         :list-unsubscribe;
        bh=OIDaDeh+Y8bPq0zRaBd5gZuzKnEu/HyEAMyXwiNi4iM=;
        b=X9HhS0Xxu11O3WjF6ebM9dN/b11+hICVlsKeRNYMUhFX6jQnNQtl4rUXO9zJKW7VaO
         kLM0mKh57ZDOSKLlWzLruT+aWroPKjsfYKnc92p/DIL8ikEy4LuiCzj1QHuN8RdSikRq
         jWM+k6laLFmBMvqScua9arTtn3GUqMma4x/0beNEEwvqFEto4uUH8LSpvek4Ug/A0YUM
         Jp6GzD22PYHQhk1gdqj2yKQCFLhU+ILhkz+Z4yOov7UThXKknh8xDqyIq6u5bzzm2IqR
         x7AjLXTfpDXefR5wqwCZtpNLHtuQQ1UYF3rQ+dP3J6Xjt6nZ/23cF/78bfFZr+FTDkpe
         DPxg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20161025;
        h=x-gm-message-state:date:from:to:cc:message-id:in-reply-to
         :references:subject:mime-version:x-original-sender:reply-to
         :precedence:mailing-list:list-id:x-spam-checked-in-group:list-post
         :list-help:list-archive:list-subscribe:list-unsubscribe;
        bh=OIDaDeh+Y8bPq0zRaBd5gZuzKnEu/HyEAMyXwiNi4iM=;
        b=A6+VvH8xS1x8Pgn0/xw2jSuTDaKbbvw9VZiqchHHh3gslE5oqYNRuHJ2+KzymCiqTa
         AkK++r7CJztyGsZqhyHI2jZwdpmYYtQSH5fy6oZQ3DxBYo5nx+brX08KDSfPeNfwKt6J
         p2sUVXX8waNTnGMK19Xo7ty05vYf3OwzTG+fuuqWWkRGd5OdAwiPkGfJQamANzSpZ25Z
         4EtuZEeaykJZ8o7y6JQIdzddIZ5ke/9YI9mfOT2+dpQeoRw9w6RjXOLhCLGiUXGPGgZo
         pRTS49WO2y11A+BNrDjocSpf9Yb3BM1rwvOwEtfhkPf2PSX/AcDxx7SZKFfPWnV7XeKG
         q6lw==
X-Gm-Message-State: APf1xPDjqfDysUaHJIivxRw6HLNJ8+vwhNJUnutIg6ZV/t4R5pOXePSb
	r5O2cbfpfIWWMoBwHvrlhKBveA==
X-Google-Smtp-Source: AH8x224594uhGSNjI+os6oIzwOlBaRrV8J0Jup3UtFlN4f4k855AEBaLmch+UQFRIDze6/f7C7HQjg==
X-Received: by 10.31.200.134 with SMTP id y128mr6334779vkf.65.1518450343705;
        Mon, 12 Feb 2018 07:45:43 -0800 (PST)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.31.67.196 with SMTP id q187ls7018750vka.21.gmail; Mon, 12 Feb
 2018 07:45:42 -0800 (PST)
X-Received: by 10.31.49.86 with SMTP id x83mr1075238vkx.0.1518450342017;
        Mon, 12 Feb 2018 07:45:42 -0800 (PST)
In-Reply-To: <5b5435db-772e-4c38-8867-f6fbc66d7cec@isocpp.org>
X-Original-Sender: jmckesson@gmail.com
Precedence: list
Mailing-list: list std-proposals@isocpp.org; contact std-proposals+owners@isocpp.org
List-ID: <std-proposals.isocpp.org>
X-Spam-Checked-In-Group: std-proposals@isocpp.org
X-Google-Group-Id: 399137483710
List-Post: <https://groups.google.com/a/isocpp.org/group/std-proposals/post>, <mailto:std-proposals@isocpp.org>
List-Help: <https://support.google.com/a/isocpp.org/bin/topic.py?topic=25838>, <mailto:std-proposals+help@isocpp.org>
List-Archive: <https://groups.google.com/a/isocpp.org/group/std-proposals/>
List-Subscribe: <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:std-proposals+subscribe@isocpp.org>
List-Unsubscribe: <mailto:googlegroups-manage+399137483710+unsubscribe@googlegroups.com>,
 <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>
Xref: news.gmane.org gmane.comp.lang.c++.isocpp.proposals:36884
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/36884>

------=_Part_9609_446297566.1518450341499
Content-Type: multipart/alternative; 
	boundary="----=_Part_9610_952126848.1518450341501"

------=_Part_9610_952126848.1518450341501
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Monday, February 12, 2018 at 10:14:25 AM UTC-5, floria...@gmail.com=20
wrote:
>
> Le lundi 12 f=C3=A9vrier 2018 15:56:12 UTC+1, Nicol Bolas a =C3=A9crit :
>>
>> On Monday, February 12, 2018 at 5:17:45 AM UTC-5, floria...@gmail.com=20
>> wrote:
>>>
>>> Let me suggest something close to Nicol's solution, but not quite.
>>>
>>> The F"" operator returns a special type that could be like a simple=20
>>> tuple (let's name it std::string_processing for now).
>>>
>>> Then the user can use it directly into its own functions.
>>>
>>>
>>> auto column =3D "col"s;
>>> auto table =3D "tab"sv;
>>> auto req =3D sql(F"select {column} from {table};");
>>>
>>> // would be equivalent to:
>>> auto req =3D sql(std::string_processing<const char[8]&, std::string&,=
=20
>>> const char[7]&, std::string_view&, const char[2]&>("select ", column, "=
=20
>>> from ", table, ";"));
>>>
>>> Now, if we want, we could also support UDL (but not mandatory) by=20
>>> allowing to call UDL on the std::string_processing:
>>>
>>> auto column =3D "col"s;
>>> auto table =3D "tab"sv;
>>> auto req =3D F"select {column} from {table};"_sql;
>>>
>>> // would be equivalent to:
>>> auto req =3D operator ""_sql (std::string_processing<const char[8]&, st=
d::
>>> string&, const char[7]&, std::string_view&, const char[2]&>("select ",=
=20
>>> column, " from ", table, ";"));
>>>
>>> Now let's have some examples of it could be:
>>>
>>> Simple string concatenation would be simple
>>> auto concatenated =3D F"{str1}{str2}{str3}"s;
>>> // converted into an efficient concatenation of the 3 strings
>>>
>>> We could print it into an iostream if we want (but would be here only=
=20
>>> for convenience on legacy code)
>>> std::cout << F"{str1}{str2}\n";
>>> // equivalent to:
>>> std::cout << str1 << str2 << "\n";
>>>
>>> It could be implicitly convertible to a std::string (only if variables=
=20
>>> are implicitly convertible to std::string)
>>> std::string concatenated =3D F"{str1}{str2}";
>>>
>>> (No example with FMT as I don't know how it works, but I don't see any=
=20
>>> reason for it not to be compatible with FMT.)
>>>
>>> And this would be constexpr-able.
>>>
>>> Now, formatting would require a bit more elaborated type that could=20
>>> store formatting information.
>>> But in the end, only the user will know what to do with it.
>>> However, I would prefer *not* to embed formatting in such a type, just=
=20
>>> to keep it simple. And use a library based solution when I really need=
=20
>>> formatting.
>>>
>>> It has all the advantages of Nicol's solution, while being more=20
>>> versatile.
>>>
>>
>> I fail to see the versatility here, and it does not have all of the=20
>> advantages of my method.
>>
>> Remember, in my version, UDLs only apply to the string fragments. In you=
r=20
>> version, you *cannot* apply UDLs to string fragments; the string=20
>> fragments will be packed into your `string_processing` type as views or=
=20
>> some such.
>>
>> Then there's ease of use. Let's see how to implement stream-based string=
=20
>> concatenation with my method:
>>
>> template<typename ...Args>
>> auto concat(Args ...&&args)
>> {
>>   std::ostringstream stream;
>>   stream << ... << std::forward<Args>(args);
>>   return std::move(stream).get();
>> }
>>
>> Simple and obvious, a standard bit of C++17 variadic template programmin=
g.
>>
>> Now, how would you go about doing that with `string_processing`? That=20
>> would require template metaprogramming:
>>
>> template<typename ...Args, size_t ...Ints>
>> void concat_items(std::ostringstream &stream, std::string_processing<Arg=
s
>> ...> &&proc, std::index_sequence<Ints...>)
>> {
>>   stream << ... << get<Ints>(proc));
>> }
>>
>> template<typename ...Args>
>> auto concat(std::string_processing<Args...> &&proc)
>> {
>>   std::ostringstream stream;
>>   concat_items(stream, std::move(proc), std::make_index_sequence<size...=
(
>> Args)>{});
>>   return std::move(stream).get();
>> }
>>
>> This isn't the hardest code to write in the world, but it is much more=
=20
>> complex than the previous one. Also, perfect forwarding doesn't really w=
ork=20
>> here.
>>
>> Also, the variadic version of `concat` can be used with stuff that isn't=
=20
>> the result of string interpolation. Or with multiple interpolated string=
s.=20
>> And so forth. Whereas your `string_processing` type is a magic type that=
=20
>> only the compiler can create. And we already have a type that does what=
=20
>> `string_processing` does; it's called `tuple`.
>>
>> The *only advantage* your method has over mine is that it allows UDLs to=
=20
>> define the aggregation operation. Why is this so important to so many=20
>> people?
>>
>>
>
> Well, my solution is more versatile in the following sense: the result is=
=20
> a plain object that can be stored in a variable, returned from a function=
..
>

tuple(F"interpolated {string}")

Oh look, "a plain object that can be stored in a variable, returned from a=
=20
function". It required a whole 7 characters more.

"Versatility" typically refers to the ability to do more things with=20
something. My way can be put into an object, but your way cannot be put=20
into a function's parameters as separate values nearly as easily. Mine=20
seems more versatile.

You could envision functions to transform std::string_processing into=20
> another std::string_processing easily.
>
> Moreover, I know that some proposals try to enable creating a parameter=
=20
> pack from a tuple (like an operator... ).
>

And sadly, none of them have advanced or even received additional revised=
=20
proposals. My way works just fine with C++ as it is.

And even if we had that, most use-cases you don't need to pass the values=
=20
around as a collective object. And if you did, you can make one trivially,=
=20
as above.

And again, it still doesn't deal with the fact that you lose perfect=20
forwarding.

With that in mind, the implementation of your concat function with my=20
> approach would be exactly the same as with your approach (with a call to=
=20
> "operator..." of std::string_processing ).
>
> And then, with only c++17 metaprogramming capabilities, you could also us=
e=20
> std::apply.
>

You cannot `apply` things to operators. Not without creating a lambda=20
function that gets called with it.

The fact is, it's a *lot* easier in C++ as it currently stands to go from=
=20
parameter pack of values to an object than it is to go from an object to a=
=20
parameter pack of values. I wish that were not the case, but so long as it=
=20
is the case, parameter packs will remain the easier-to-use option.

UDL the aggregate is not important to me, but it was easy to include and=20
> allows neat syntax (in my opinion).
>

But it makes it impossible to apply a UDL to the string fragments. And=20
that's important if you do want to use template metaprogramming on string=
=20
literals.

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/5c51d89a-54b6-490b-87f2-09ed263d8322%40isocpp.or=
g.

------=_Part_9610_952126848.1518450341501
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Monday, February 12, 2018 at 10:14:25 AM UTC-5, floria.=
...@gmail.com wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;mar=
gin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D=
"ltr">Le lundi 12 f=C3=A9vrier 2018 15:56:12 UTC+1, Nicol Bolas a =C3=A9cri=
t=C2=A0:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8=
ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">On Monday,=
 February 12, 2018 at 5:17:45 AM UTC-5, <a>floria...@gmail.com</a> wrote:<b=
lockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-=
left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">Let me suggest somet=
hing close to Nicol&#39;s solution, but not quite.<br><br>The F&quot;&quot;=
 operator returns a special type that could be like a simple tuple (let&#39=
;s name it std::string_processing for now).<br><br>Then the user can use it=
 directly into its own functions.<br><br><br><div style=3D"background-color=
:rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;border-w=
idth:1px"><code><div><span style=3D"color:#008">auto</span><span style=3D"c=
olor:#000"> column </span><span style=3D"color:#660">=3D</span><span style=
=3D"color:#000"> </span><span style=3D"color:#080">&quot;col&quot;</span><s=
pan style=3D"color:#000">s</span><span style=3D"color:#660">;</span><span s=
tyle=3D"color:#000"><br></span><span style=3D"color:#008">auto</span><span =
style=3D"color:#000"> table </span><span style=3D"color:#660">=3D</span><sp=
an style=3D"color:#000"> </span><span style=3D"color:#080">&quot;tab&quot;<=
/span><span style=3D"color:#000">sv</span><span style=3D"color:#660">;</spa=
n><span style=3D"color:#000"><br></span><span style=3D"color:#008">auto</sp=
an><span style=3D"color:#000"> req </span><span style=3D"color:#660">=3D</s=
pan><span style=3D"color:#000"> sql</span><span style=3D"color:#660">(</spa=
n><span style=3D"color:#000">F</span><span style=3D"color:#080">&quot;selec=
t {column} from {table};&quot;</span><span style=3D"color:#660">);</span><s=
pan style=3D"color:#000"><br><br></span><span style=3D"color:#800">// would=
 be equivalent to:</span><span style=3D"color:#000"><br></span><span style=
=3D"color:#008">auto</span><span style=3D"color:#000"> req </span><span sty=
le=3D"color:#660">=3D</span><span style=3D"color:#000"> sql</span><span sty=
le=3D"color:#660">(</span><span style=3D"color:#000">std</span><span style=
=3D"color:#660">::</span><span style=3D"color:#000">string_processing</span=
><span style=3D"color:#660">&lt;</span><span style=3D"color:#008">con<wbr>s=
t</span><span style=3D"color:#000"> </span><span style=3D"color:#008">char<=
/span><span style=3D"color:#660">[</span><span style=3D"color:#066">8</span=
><span style=3D"color:#660">]&amp;,</span><span style=3D"color:#000"> std</=
span><span style=3D"color:#660">::</span><span style=3D"color:#008">string<=
/span><span style=3D"color:#660">&amp;,</span><span style=3D"color:#000"> <=
/span><span style=3D"color:#008">const</span><span style=3D"color:#000"> </=
span><span style=3D"color:#008">char</span><span style=3D"color:#660">[</sp=
an><span style=3D"color:#066">7</span><span style=3D"color:#660">]&amp;,</s=
pan><span style=3D"color:#000"> std</span><span style=3D"color:#660">::</sp=
an><span style=3D"color:#000">string_view</span><span style=3D"color:#660">=
&amp;,</span><span style=3D"color:#000"> </span><span style=3D"color:#008">=
const</span><span style=3D"color:#000"> </span><span style=3D"color:#008">c=
har</span><span style=3D"color:#660">[</span><span style=3D"color:#066">2</=
span><span style=3D"color:#660">]&amp;&gt;(</span><span style=3D"color:#080=
">&quot;select &quot;</span><span style=3D"color:#660">,</span><span style=
=3D"color:#000"> column</span><span style=3D"color:#660">,</span><span styl=
e=3D"color:#000"> </span><span style=3D"color:#080">&quot; from &quot;</spa=
n><span style=3D"color:#660">,</span><span style=3D"color:#000"> table</spa=
n><span style=3D"color:#660">,</span><span style=3D"color:#000"> </span><sp=
an style=3D"color:#080">&quot;;&quot;</span><span style=3D"color:#660">));<=
/span><span style=3D"color:#000"><br></span></div></code></div><br>Now, if =
we want, we could also support UDL (but not mandatory) by allowing to call =
UDL on the std::string_processing:<br><br><div style=3D"background-color:rg=
b(250,250,250);border-color:rgb(187,187,187);border-style:solid;border-widt=
h:1px"><code><div><span style=3D"color:#008">auto</span><span style=3D"colo=
r:#000"> column </span><span style=3D"color:#660">=3D</span><span style=3D"=
color:#000"> </span><span style=3D"color:#080">&quot;col&quot;</span><span =
style=3D"color:#000">s</span><span style=3D"color:#660">;</span><span style=
=3D"color:#000"><br></span><span style=3D"color:#008">auto</span><span styl=
e=3D"color:#000"> table </span><span style=3D"color:#660">=3D</span><span s=
tyle=3D"color:#000"> </span><span style=3D"color:#080">&quot;tab&quot;</spa=
n><span style=3D"color:#000">sv</span><span style=3D"color:#660">;</span><s=
pan style=3D"color:#000"><br></span><span style=3D"color:#008">auto</span><=
span style=3D"color:#000"> req </span><span style=3D"color:#660">=3D</span>=
<span style=3D"color:#000"> F</span><span style=3D"color:#080">&quot;select=
 {column} from {table};&quot;</span><span style=3D"color:#000">_sql</span><=
span style=3D"color:#660">;</span><span style=3D"color:#000"><br><br></span=
><span style=3D"color:#800">// would be equivalent to:</span><span style=3D=
"color:#000"><br></span><span style=3D"color:#008">auto</span><span style=
=3D"color:#000"> req </span><span style=3D"color:#660">=3D</span><span styl=
e=3D"color:#000"> </span><span style=3D"color:#008">operator</span><span st=
yle=3D"color:#000"> </span><span style=3D"color:#080">&quot;&quot;</span><s=
pan style=3D"color:#000">_sql </span><span style=3D"color:#660">(</span><sp=
an style=3D"color:#000">std</span><span style=3D"color:#660">::</span><span=
 style=3D"color:#000">string_processing</span><span style=3D"color:#660">&l=
t;</span><span style=3D"color:#008">const</span><span style=3D"color:#000">=
 </span><span style=3D"color:#008">char</span><span style=3D"color:#660">[<=
/span><span style=3D"color:#066">8</span><span style=3D"color:#660">]&amp;,=
</span><span style=3D"color:#000"> std</span><span style=3D"color:#660">::<=
/span><span style=3D"color:#008">string</span><span style=3D"color:#660">&a=
mp;,</span><span style=3D"color:#000"> </span><span style=3D"color:#008">co=
nst</span><span style=3D"color:#000"> </span><span style=3D"color:#008">cha=
r</span><span style=3D"color:#660">[</span><span style=3D"color:#066">7</sp=
an><span style=3D"color:#660">]&amp;,</span><span style=3D"color:#000"> std=
</span><span style=3D"color:#660">::</span><span style=3D"color:#000">strin=
g_view</span><span style=3D"color:#660">&amp;,</span><span style=3D"color:#=
000"> </span><span style=3D"color:#008">const</span><span style=3D"color:#0=
00"> </span><span style=3D"color:#008">char</span><span style=3D"color:#660=
">[</span><span style=3D"color:#066">2</span><span style=3D"color:#660">]&a=
mp;&gt;(</span><span style=3D"color:#080">&quot;select &quot;</span><span s=
tyle=3D"color:#660">,</span><span style=3D"color:#000"> column</span><span =
style=3D"color:#660">,</span><span style=3D"color:#000"> </span><span style=
=3D"color:#080">&quot; from &quot;</span><span style=3D"color:#660">,</span=
><span style=3D"color:#000"> table</span><span style=3D"color:#660">,</span=
><span style=3D"color:#000"> </span><span style=3D"color:#080">&quot;;&quot=
;</span><span style=3D"color:#660">));</span><span style=3D"color:#000"><br=
></span></div></code></div><br>Now let&#39;s have some examples of it could=
 be:<br><br>Simple string concatenation would be simple<br><div style=3D"ba=
ckground-color:rgb(250,250,250);border-color:rgb(187,187,187);border-style:=
solid;border-width:1px"><code><div><span style=3D"color:#008">auto</span><s=
pan style=3D"color:#000"> concatenated </span><span style=3D"color:#660">=
=3D</span><span style=3D"color:#000"> F</span><span style=3D"color:#080">&q=
uot;{str1}{str2}{str3}&quot;</span><span style=3D"color:#000">s</span><span=
 style=3D"color:#660">;</span><span style=3D"color:#000"><br></span><span s=
tyle=3D"color:#800">// converted into an efficient concatenation of the 3 s=
trings</span><span style=3D"color:#000"><br></span></div></code></div><br>W=
e could print it into an iostream if we want (but would be here only for co=
nvenience on legacy code)<br><div style=3D"background-color:rgb(250,250,250=
);border-color:rgb(187,187,187);border-style:solid;border-width:1px"><code>=
<div><span style=3D"color:#000">std</span><span style=3D"color:#660">::</sp=
an><span style=3D"color:#000">cout </span><span style=3D"color:#660">&lt;&l=
t;</span><span style=3D"color:#000"> F</span><span style=3D"color:#080">&qu=
ot;{str1}{str2}\n&quot;</span><span style=3D"color:#660">;</span><span styl=
e=3D"color:#000"><br></span><span style=3D"color:#800">// equivalent to:</s=
pan><span style=3D"color:#000"><br>std</span><span style=3D"color:#660">::<=
/span><span style=3D"color:#000">cout </span><span style=3D"color:#660">&lt=
;&lt;</span><span style=3D"color:#000"> str1 </span><span style=3D"color:#6=
60">&lt;&lt;</span><span style=3D"color:#000"> str2 </span><span style=3D"c=
olor:#660">&lt;&lt;</span><span style=3D"color:#000"> </span><span style=3D=
"color:#080">&quot;\n&quot;</span><span style=3D"color:#660">;</span><span =
style=3D"color:#000"><br></span></div></code></div><br>It could be implicit=
ly convertible to a std::string (only if variables are implicitly convertib=
le to std::string)<br><div style=3D"background-color:rgb(250,250,250);borde=
r-color:rgb(187,187,187);border-style:solid;border-width:1px"><code><div><s=
pan style=3D"color:#000">std</span><span style=3D"color:#660">::</span><spa=
n style=3D"color:#008">string</span><span style=3D"color:#000"> concatenate=
d </span><span style=3D"color:#660">=3D</span><span style=3D"color:#000"> F=
</span><span style=3D"color:#080">&quot;{str1}{str2}&quot;</span><span styl=
e=3D"color:#660">;</span><span style=3D"color:#000"><br></span></div></code=
></div><br>(No example with FMT as I don&#39;t know how it works, but I don=
&#39;t see any reason for it not to be compatible with FMT.)<br><br>And thi=
s would be constexpr-able.<br><br>Now, formatting would require a bit more =
elaborated type that could store formatting information.<br>But in the end,=
 only the user will know what to do with it.<br>However, I would prefer <b>=
not</b> to embed formatting in such a type, just to keep it simple. And use=
 a library based solution when I really need formatting.<br><br>It has all =
the advantages of Nicol&#39;s solution, while being more versatile.<br></di=
v></blockquote><div><br>I fail to see the versatility here, and it does not=
 have all of the advantages of my method.<br><br>Remember, in my version, U=
DLs only apply to the string fragments. In your version, you <i>cannot</i> =
apply UDLs to string fragments; the string fragments will be packed into yo=
ur `string_processing` type as views or some such.<br><br>Then there&#39;s =
ease of use. Let&#39;s see how to implement stream-based string concatenati=
on with my method:<br><br><div style=3D"background-color:rgb(250,250,250);b=
order-color:rgb(187,187,187);border-style:solid;border-width:1px"><code><di=
v><span style=3D"color:#008">template</span><span style=3D"color:#660">&lt;=
</span><span style=3D"color:#008">typename</span><span style=3D"color:#000"=
> </span><span style=3D"color:#660">...</span><span style=3D"color:#606">Ar=
gs</span><span style=3D"color:#660">&gt;</span><span style=3D"color:#000"><=
br></span><span style=3D"color:#008">auto</span><span style=3D"color:#000">=
 concat</span><span style=3D"color:#660">(</span><span style=3D"color:#606"=
>Args</span><span style=3D"color:#000"> </span><span style=3D"color:#660">.=
...&amp;&amp;</span><span style=3D"color:#000">args</span><span style=3D"col=
or:#660">)</span><span style=3D"color:#000"><br></span><span style=3D"color=
:#660">{</span><span style=3D"color:#000"><br>=C2=A0 std</span><span style=
=3D"color:#660">::</span><span style=3D"color:#000">ostringstream stream</s=
pan><span style=3D"color:#660">;</span><span style=3D"color:#000"><br>=C2=
=A0 stream </span><span style=3D"color:#660">&lt;&lt;</span><span style=3D"=
color:#000"> </span><span style=3D"color:#660">...</span><span style=3D"col=
or:#000"> </span><span style=3D"color:#660">&lt;&lt;</span><span style=3D"c=
olor:#000"> std</span><span style=3D"color:#660">::</span><span style=3D"co=
lor:#000">forward</span><span style=3D"color:#660">&lt;</span><span style=
=3D"color:#606">Args</span><span style=3D"color:#660">&gt;(</span><span sty=
le=3D"color:#000">args</span><span style=3D"color:#660">);</span><span styl=
e=3D"color:#000"><br>=C2=A0 </span><span style=3D"color:#008">return</span>=
<span style=3D"color:#000"> std</span><span style=3D"color:#660">::</span><=
span style=3D"color:#000">move</span><span style=3D"color:#660">(</span><sp=
an style=3D"color:#000">stream</span><span style=3D"color:#660">).</span><s=
pan style=3D"color:#008">get</span><span style=3D"color:#660">();</span><sp=
an style=3D"color:#000"><br></span><span style=3D"color:#660">}</span></div=
></code></div><br>Simple and obvious, a standard bit of C++17 variadic temp=
late programming.<br><br>Now, how would you go about doing that with `strin=
g_processing`? That would require template metaprogramming:<br><br><div sty=
le=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);borde=
r-style:solid;border-width:1px"><code><div><span style=3D"color:#008">templ=
ate</span><span style=3D"color:#660">&lt;</span><span style=3D"color:#008">=
typename</span><span style=3D"color:#000"> </span><span style=3D"color:#660=
">...</span><span style=3D"color:#606">Args</span><span style=3D"color:#660=
">,</span><span style=3D"color:#000"> size_t </span><span style=3D"color:#6=
60">...</span><span style=3D"color:#606">Ints</span><span style=3D"color:#6=
60">&gt;</span><span style=3D"color:#000"><br></span><span style=3D"color:#=
008">void</span><span style=3D"color:#000"> concat_items</span><span style=
=3D"color:#660">(</span><span style=3D"color:#000">std</span><span style=3D=
"color:#660">::</span><span style=3D"color:#000">ostringstrea<wbr>m </span>=
<span style=3D"color:#660">&amp;</span><span style=3D"color:#000">stream</s=
pan><span style=3D"color:#660">,</span><span style=3D"color:#000"> std</spa=
n><span style=3D"color:#660">::</span><span style=3D"color:#000">string_pro=
cessing</span><span style=3D"color:#660">&lt;</span><span style=3D"color:#6=
06">Args</span><span style=3D"color:#660">...<wbr>&gt;</span><span style=3D=
"color:#000"> </span><span style=3D"color:#660">&amp;&amp;</span><span styl=
e=3D"color:#000">proc</span><span style=3D"color:#660">,</span><span style=
=3D"color:#000"> std</span><span style=3D"color:#660">::</span><span style=
=3D"color:#000">index_sequence</span><span style=3D"color:#660">&lt;</span>=
<span style=3D"color:#606">Ints</span><span style=3D"color:#660">...&gt;)</=
span><span style=3D"color:#000"><br></span><span style=3D"color:#660">{</sp=
an><span style=3D"color:#000"><br>=C2=A0 stream </span><span style=3D"color=
:#660">&lt;&lt;</span><span style=3D"color:#000"> </span><span style=3D"col=
or:#660">...</span><span style=3D"color:#000"> </span><span style=3D"color:=
#660">&lt;&lt;</span><span style=3D"color:#000"> </span><span style=3D"colo=
r:#008">get</span><span style=3D"color:#660">&lt;</span><span style=3D"colo=
r:#606">Ints</span><span style=3D"color:#660">&gt;(</span><span style=3D"co=
lor:#000">proc</span><span style=3D"color:#660">));</span><span style=3D"co=
lor:#000"><br></span><span style=3D"color:#660">}</span><span style=3D"colo=
r:#000"><br><br></span><span style=3D"color:#008">template</span><span styl=
e=3D"color:#660">&lt;</span><span style=3D"color:#008">typename</span><span=
 style=3D"color:#000"> </span><span style=3D"color:#660">...</span><span st=
yle=3D"color:#606">Args</span><span style=3D"color:#660">&gt;</span><span s=
tyle=3D"color:#000"><br></span><span style=3D"color:#008">auto</span><span =
style=3D"color:#000"> concat</span><span style=3D"color:#660">(</span><span=
 style=3D"color:#000">std</span><span style=3D"color:#660">::</span><span s=
tyle=3D"color:#000">string_processing</span><span style=3D"color:#660">&lt;=
</span><span style=3D"color:#606"><wbr>Args</span><span style=3D"color:#660=
">...&gt;</span><span style=3D"color:#000"> </span><span style=3D"color:#66=
0">&amp;&amp;</span><span style=3D"color:#000">proc</span><span style=3D"co=
lor:#660">)</span><span style=3D"color:#000"><br></span><span style=3D"colo=
r:#660">{</span><span style=3D"color:#000"><br>=C2=A0 std</span><span style=
=3D"color:#660">::</span><span style=3D"color:#000">ostringstream stream</s=
pan><span style=3D"color:#660">;</span><span style=3D"color:#000"><br>=C2=
=A0 concat_items</span><span style=3D"color:#660">(</span><span style=3D"co=
lor:#000">stream</span><span style=3D"color:#660">,</span><span style=3D"co=
lor:#000"> std</span><span style=3D"color:#660">::</span><span style=3D"col=
or:#000">move</span><span style=3D"color:#660">(</span><span style=3D"color=
:#000">proc</span><span style=3D"color:#660">),</span><span style=3D"color:=
#000"> std</span><span style=3D"color:#660">::</span><span style=3D"color:#=
000">make_index_sequence</span><span style=3D"color:#660">&lt;</span><span =
style=3D"color:#000">size</span><span style=3D"color:#660">.<wbr>..(</span>=
<span style=3D"color:#606">Args</span><span style=3D"color:#660">)&gt;{});<=
/span><span style=3D"color:#000"><br>=C2=A0 </span><span style=3D"color:#00=
8">return</span><span style=3D"color:#000"> std</span><span style=3D"color:=
#660">::</span><span style=3D"color:#000">move</span><span style=3D"color:#=
660">(</span><span style=3D"color:#000">stream</span><span style=3D"color:#=
660">).</span><span style=3D"color:#008">get</span><span style=3D"color:#66=
0">();</span><span style=3D"color:#000"><br></span><span style=3D"color:#66=
0">}</span></div></code></div><br>This isn&#39;t the hardest code to write =
in the world, but it is much more complex than the previous one. Also, perf=
ect forwarding doesn&#39;t really work here.<br><br>Also, the variadic vers=
ion of `concat` can be used with stuff that isn&#39;t the result of string =
interpolation. Or with multiple interpolated strings. And so forth. Whereas=
 your `string_processing` type is a magic type that only the compiler can c=
reate. And we already have a type that does what `string_processing` does; =
it&#39;s called `tuple`.<br><br>The <i>only advantage</i> your method has o=
ver mine is that it allows UDLs to define the aggregation operation. Why is=
 this so important to so many people?<br></div><br></div></blockquote><div>=
<br></div><br><div>Well, my solution is more versatile in the following sen=
se: the=20
result is a plain object that can be stored in a variable, returned from
 a function.</div></div></blockquote><div><br><div style=3D"background-colo=
r: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: soli=
d; border-width: 1px; overflow-wrap: break-word;" class=3D"prettyprint"><co=
de class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color=
: #000;" class=3D"styled-by-prettify">tuple</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">F</span><span style=3D"color: #080;" class=3D"style=
d-by-prettify">&quot;interpolated {string}&quot;</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">)</span></div></code></div><br>Oh loo=
k, &quot;a plain object that can be stored in a variable, returned from
 a function&quot;. It required a whole 7 characters more.<br><br>&quot;Vers=
atility&quot; typically refers to the ability to do more things with someth=
ing. My way can be put into an object, but your way cannot be put into a fu=
nction&#39;s parameters as separate values nearly as easily. Mine seems mor=
e versatile.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin=
: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div=
 dir=3D"ltr"><div>You could envision functions to transform std::string_pro=
cessing into another std::string_processing easily.</div><div><br></div><di=
v>Moreover, I know that some proposals try to enable creating a parameter p=
ack from a tuple (like an operator... ).</div></div></blockquote><div><br>A=
nd sadly, none of them have advanced or even received additional revised pr=
oposals. My way works just fine with C++ as it is.<br><br>And even if we ha=
d that, most use-cases you don&#39;t need to pass the values around as a co=
llective object. And if you did, you can make one trivially, as above.<br><=
br>And again, it still doesn&#39;t deal with the fact that you lose perfect=
 forwarding.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin=
: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div=
 dir=3D"ltr"><div>With that in mind, the implementation of your concat func=
tion with my approach would be exactly the same as with your approach (with=
 a call to &quot;operator...&quot; of std::string_processing ).</div><div><=
br></div><div>And then, with only c++17 metaprogramming capabilities, you c=
ould also use std::apply.<br></div></div></blockquote><div><br>You cannot `=
apply` things to operators. Not without creating a lambda function that get=
s called with it.<br><br>The fact is, it&#39;s a <i>lot</i> easier in C++ a=
s it currently stands to go from parameter pack of values to an object than=
 it is to go from an object to a parameter pack of values. I wish that were=
 not the case, but so long as it is the case, parameter packs will remain t=
he easier-to-use option.<br><br></div><blockquote class=3D"gmail_quote" sty=
le=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left=
: 1ex;"><div dir=3D"ltr"><div></div><div></div>UDL the aggregate is not imp=
ortant to me, but it was easy to include and allows neat syntax (in my opin=
ion).<br></div></blockquote><div><br>But it makes it impossible to apply a =
UDL to the string fragments. And that&#39;s important if you do want to use=
 template metaprogramming on string literals.<br><br></div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/5c51d89a-54b6-490b-87f2-09ed263d8322%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/5c51d89a-54b6-490b-87f2-09ed263d8322=
%40isocpp.org</a>.<br />

------=_Part_9610_952126848.1518450341501--

------=_Part_9609_446297566.1518450341499--

.
