220 36902 <3468ee0c-a44a-437a-a835-0156c623df2e@isocpp.org> article
Path: news.gmane.org!.POSTED!not-for-mail
From: florian.csdt@gmail.com
Newsgroups: gmane.comp.lang.c++.isocpp.proposals
Subject: Re: String interpolation
Date: Tue, 13 Feb 2018 09:18:59 -0800 (PST)
Lines: 730
Approved: news@gmane.org
Message-ID: <3468ee0c-a44a-437a-a835-0156c623df2e@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>
 <5c51d89a-54b6-490b-87f2-09ed263d8322@isocpp.org>
 <305b7669-0744-473e-9715-807b7e8051b6@isocpp.org>
 <0ceb2063-d7b6-4cb8-8c5c-c63aceb5b549@isocpp.org>
 <d26b85c2-707b-49a5-a007-617027506dd1@isocpp.org>
 <41b87b07-1a91-4bca-ba00-5734c09dbe77@isocpp.org>
 <ef8fbc4c-08c0-409e-815b-28e161101231@isocpp.org>
 <1a7f714d-4a91-4a95-8da4-0c688d18c4c4@isocpp.org>
 <5f8efcc0-f4e9-4518-abe5-5fffeab55083@isocpp.org>
 <0e0876bb-7a44-45ff-ab9b-6443e78ea59c@isocpp.org>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: blaine.gmane.org
Mime-Version: 1.0
Content-Type: multipart/mixed; 
	boundary="----=_Part_11923_890054300.1518542339405"
X-Trace: blaine.gmane.org 1518542252 26183 195.159.176.226 (13 Feb 2018 17:17:32 GMT)
X-Complaints-To: usenet@blaine.gmane.org
NNTP-Posting-Date: Tue, 13 Feb 2018 17:17:32 +0000 (UTC)
To: ISO C++ Standard - Future Proposals <std-proposals@isocpp.org>
Original-X-From: std-proposals+bncBC26HM4V3MIRBBF4RTKAKGQE55U7QWI@isocpp.org Tue Feb 13 18:17:27 2018
Return-path: <std-proposals+bncBC26HM4V3MIRBBF4RTKAKGQE55U7QWI@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-ua0-f199.google.com ([209.85.217.199])
	by blaine.gmane.org with esmtp (Exim 4.84_2)
	(envelope-from <std-proposals+bncBC26HM4V3MIRBBF4RTKAKGQE55U7QWI@isocpp.org>)
	id 1eleCO-0004ZE-VZ
	for gclcip-std-proposals@m.gmane.org; Tue, 13 Feb 2018 18:16:57 +0100
Original-Received: by mail-ua0-f199.google.com with SMTP id z11sf13132950uaz.0
        for <gclcip-std-proposals@m.gmane.org>; Tue, 13 Feb 2018 09:19:03 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=isocpp-org.20150623.gappssmtp.com; s=20150623;
        h=date:from:to: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=+rfXeC5EenMVdn9pwV/YCFH0aX/Y6Un2WzuRBtD2PoI=;
        b=yzNtLqPiY6j7Arm4GBmeHz87RwDfhCWbZzRmDco3ToQ5NJafTymDw/AOmx4XAxRhsX
         DhMeuFs11hQdHNY7Wu8YelWYdBAWrx6fMtUg1N51B7KBxD7jFdWc5zN0vBOuncakTQnS
         Xyer/FH2DpCaYRa6cJyQ49KGxixA+0oVEZOjI9w0XzB1JdoGa+2AQsYzAa/GJewJfq9f
         ihaivg/Ar2JZ/tCumVa7w42H2oJkjgxHtG05j8EqWKFnY1nHStaWKyX3/nC+hXR3xgqH
         hgwMtIoEjNmTDtwLJpHEKh+wQBKL/DLRAX7tYMr6k/Mz+Q59kKXaTkq+PsvY98gPGJEO
         tJsQ==
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=20161025;
        h=date:from:to: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=+rfXeC5EenMVdn9pwV/YCFH0aX/Y6Un2WzuRBtD2PoI=;
        b=rSpaDvuewAzGkAe+0NGJhzzFHoCSPBBy8Ta6l9KRbJDbzoEPJ3CRc7MyaS0Yoz8Oqo
         ajF6daqbC5TRyZ5k6XDRqsxEwxbMEpSq1CvKgWhi7EOTsgzc7i/n+TsF4Zxbi6fYYSms
         tKMc3uKEPF0WT4dad8PCR2UfYe1wVVHCn9enJXLc25XHLz1lDj//s33+2w1JQabVzhss
         PUIiEKofMA1Tt+Xc7xf235t+DvIDTgz9OTRRVPracR0XCNY79XOmIdXb7mFhuGtvLRP0
         NecloTeaSCLIAZFOpQCQBYL90SrTgPdj4bj0v12s42SuIcjHuVwjFzqGwR4G0EVblj8W
         EW6w==
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: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=+rfXeC5EenMVdn9pwV/YCFH0aX/Y6Un2WzuRBtD2PoI=;
        b=erWdHLVVEU4JdFQjt8GK99g6SY5npS8AOYsSDXzPtCyQeftucsdbc936kWE94mKrk4
         53ZmQlDeehqQe8RvLlGZPvZKgQ9rOzW/11dxLT2+rnW1Lze8SXxwfmpPJ7azG1R4PRPT
         H2t1nyEpAa6RdPp13R9JEmBz0dWKrW9jfP/xHPJq8357FqtHIupvC1Fo57WYt2rQ4AkU
         4ulMIulKibYgOQpz4os8alqjYSTJGd5DA/h+S2Rcys6pAb+lKT/uVV//1qN4fF4cjisB
         rSndSroUWd7jiF0vekFqv6a10T9NsXvfgcxGLjWoCwi9pjw/woFFsXbcMSOhaLGNId/z
         mh2w==
X-Gm-Message-State: APf1xPBeDEMM5DKB5R40V2XgFbTMgHmfQQmG5MpQ0JPvnByuVKMLNaQR
	KjOiTYS7OW2wQAp/mh0steZH3w==
X-Google-Smtp-Source: AH8x224f4Xr337JOGear6Mg4xO5tW/prUJhVhnPy15oKE0TGXYyDFA6a0xVhOc5UkAtdWyWOeENOtw==
X-Received: by 10.31.204.129 with SMTP id c123mr955399vkg.120.1518542342562;
        Tue, 13 Feb 2018 09:19:02 -0800 (PST)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.31.169.142 with SMTP id s136ls9459082vke.18.gmail; Tue, 13 Feb
 2018 09:19:00 -0800 (PST)
X-Received: by 10.31.158.65 with SMTP id h62mr167264vke.4.1518542340109;
        Tue, 13 Feb 2018 09:19:00 -0800 (PST)
In-Reply-To: <0e0876bb-7a44-45ff-ab9b-6443e78ea59c@isocpp.org>
X-Original-Sender: florian.csdt@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:36902
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/36902>

------=_Part_11923_890054300.1518542339405
Content-Type: multipart/alternative; 
	boundary="----=_Part_11924_21200749.1518542339406"

------=_Part_11924_21200749.1518542339406
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable



Le mardi 13 f=C3=A9vrier 2018 17:35:49 UTC+1, Nicol Bolas a =C3=A9crit :
>
> On Tuesday, February 13, 2018 at 4:50:00 AM UTC-5, floria...@gmail.com=20
> wrote:
>>
>> Le mardi 13 f=C3=A9vrier 2018 07:28:45 UTC+1, Nicol Bolas a =C3=A9crit :
>>>
>>> On Monday, February 12, 2018 at 4:08:37 PM UTC-5, floria...@gmail.com=
=20
>>> wrote:
>>>>
>>>> Le lundi 12 f=C3=A9vrier 2018 21:11:14 UTC+1, Nicol Bolas a =C3=A9crit=
 :
>>>>>
>>>>> On Monday, February 12, 2018 at 12:43:41 PM UTC-5, floria...@gmail.co=
m=20
>>>>> wrote:
>>>>>>
>>>>>> Le lundi 12 f=C3=A9vrier 2018 17:56:48 UTC+1, Nicol Bolas a =C3=A9cr=
it :
>>>>>>>
>>>>>>> On Monday, February 12, 2018 at 11:15:33 AM UTC-5,=20
>>>>>>> floria...@gmail.com wrote:
>>>>>>>
>>>>>> With that in mind, the implementation of your concat function with m=
y=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 coul=
d=20
>>>>>>>>>> also use std::apply.
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> You cannot `apply` things to operators. Not without creating a=20
>>>>>>>>> lambda function that gets called with it.
>>>>>>>>>
>>>>>>>> =20
>>>>>>>> Why not? You can get the address of an operator, and this is a=20
>>>>>>>> callable object.
>>>>>>>>
>>>>>>>
>>>>>>> You can only get the address of a single overload of an operator.=
=20
>>>>>>> Remember: the whole idea is that you're dealing with a sequence of=
=20
>>>>>>> variables of different types. So the second parameter to the operat=
or has=20
>>>>>>> to be of different types for different invocations of the operator.
>>>>>>>
>>>>>>
>>>>>> This is another quirk of C++ that should be fixed.
>>>>>>
>>>>>
>>>>> Which incidentally is yet another proposal (lifting lambdas) that=20
>>>>> stalled.
>>>>>
>>>>> The fact is, it's a *lot* easier in C++ as it currently stands to go=
=20
>>>>>>>>> from parameter pack of values to an object than it is to go from =
an object=20
>>>>>>>>> to a parameter pack of values. I wish that were not the case, but=
 so long=20
>>>>>>>>> as it is the case, parameter packs will remain the easier-to-use =
option.
>>>>>>>>>
>>>>>>>> =20
>>>>>>>> You have a point.=20
>>>>>>>>
>>>>>>>>
>>>>>>>>> UDL the aggregate is not important to me, but it was easy to=20
>>>>>>>>>> include and allows neat syntax (in my opinion).
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> But it makes it impossible to apply a UDL to the string fragments=
..=20
>>>>>>>>> And that's important if you do want to use template metaprogrammi=
ng on=20
>>>>>>>>> string literals.
>>>>>>>>>
>>>>>>>>
>>>>>>>> I'm not sure to see the use case here. When you use UDL, you want=
=20
>>>>>>>> the whole literal to be what you say it would be.
>>>>>>>> auto s =3D "something"s; // s is a string
>>>>>>>> auto sv =3D "some other"sv; // s is a string view
>>>>>>>> We are not interested in what is happening in the middle. I don't=
=20
>>>>>>>> why it should be different with string interpolation (or whatever =
the name=20
>>>>>>>> is).
>>>>>>>>
>>>>>>>
>>>>>>> Because not all of the "literal" is actually a literal anymore.=20
>>>>>>> That's the whole point of string interpolation: you're taking a lit=
eral and=20
>>>>>>> you're augmenting it with some non-literal data. Potentially=20
>>>>>>> *runtime* non-literal data. It isn't a literal anymore, so the UDL=
=20
>>>>>>> suffix can't apply to the aggregate. It can only apply to the indiv=
idual=20
>>>>>>> literal fragments of the string.
>>>>>>>
>>>>>>
>>>>>> Here, I don't care if it's called a literal, or if we invent a new=
=20
>>>>>> name for this concept that appeared to match the concept of literal =
when=20
>>>>>> "string interpolation" was not a thing.
>>>>>> I'm more interested in the final syntax as the end user will see it.
>>>>>>
>>>>>> And I would prefer concatenate like this:
>>>>>> auto s =3D F"{str1}{str2}{str3}"s;
>>>>>> than this:
>>>>>> auto s =3D std::concat(F"{str1}{str2}{str3}");
>>>>>>
>>>>>> The first one looks more natural in my opinion.
>>>>>>
>>>>>
>>>>> It only looks more natural for the trivial cases. Consider what=20
>>>>> `std::concat` would look like. It creates an `ostringstream`, applies=
 it to=20
>>>>> each parameter, and moves its result out. Why pick `ostringstream`? W=
hy not=20
>>>>> allow the user to decide which kind of stream to use and therefore wh=
ich=20
>>>>> resulting string type to build?
>>>>>
>>>>
>>>> I never said this should work only with UDL. I just said that I think=
=20
>>>> it is more natural if UDL worked like that.
>>>> But I really think the user should keep control over what can be done=
=20
>>>> with this syntax.
>>>> So I totally agree with you: users should be able to call their own=20
>>>> functions with it.
>>>>
>>>> And then, even considering F"{str1}{str2}{str3}"s for concatenating, I=
=20
>>>> never mentionned std::ostringstream, I just said converted into an=20
>>>> efficient way of concatenating strings.
>>>> In that case, I just considered that when we use operator ""s, we want=
=20
>>>> a std::string.
>>>>
>>>
>>> You say that the literal `s` means you want a `std::string`. But that's=
=20
>>> not enough information, because you now have to define how to *get* a=
=20
>>> `std::string` from values that aren't `std::string`. That's why you nee=
d=20
>>> more information than a mere literal can provide.
>>>
>>> There are many ways to get a std::string from an interpolated string.=
=20
>>> Your `operator""s` will only be doing one of them. That mechanism will =
be=20
>>> *fixed*. Inflexible. Unchangeable.
>>>
>>
>> I never said here the this operator ""s should work with this: F"foo {5}=
=20
>> bar"s... To be fair, I have been thinking this should work only if every=
=20
>> single part is convertible to std::string. So the result is unambiguous,=
 so=20
>> it doesn't matter if it is fixed, unchangeable.
>> And if you want a function call, do a function call, it will work.
>> =20
>>
>>>
>>> That's bad. A function call will be more versatile.
>>>
>>> You can't do that with a UDL; they can't take an extra template=20
>>>>> parameter. `std::concat` can.
>>>>>
>>>>
>>>> To do that, just use a function. We can have multiple syntaxes to do=
=20
>>>> the same thing.
>>>> The closest example I can think of is:
>>>> auto s =3D std::string("str");
>>>> // is equivalent to
>>>> auto s =3D "str"s;
>>>>
>>>>
>>> No, it's not:
>>>
>>> auto s1 =3D std::string("str\0str");
>>> auto s2 =3D "str\0str"s;
>>>
>>> In `s1` the constructor has to do `char_traits<char>::length` to comput=
e=20
>>> the number of characters in the string. That will terminate the string =
at=20
>>> the first NUL character. In the second case, the UDL gets the size from=
 the=20
>>> literal parameter directly.
>>>
>>> Things like this are why it is important to separate literal operations=
=20
>>> from string interpolation. So that UDLs can do the job they exist to do=
=20
>>> (literal synthesis) and string interpolation can do the job its meant t=
o do=20
>>> (breaking down literals into sequences of values). And the aggregation =
can=20
>>> do the job its meant to do (take sequences of values and act on them).
>>>
>>
>> String literals are broken now. This is not fixable by UDL currently. So=
=20
>> all in all, we are doomed here.
>>
> If you write a function that need to take std::string_view for literal=20
>> parts, let's do that, you don't need to force the literal to be a=20
>> string_view to work, as they are implicitly convertible from const char[=
]&.=20
>> The same with std::string.
>> No, forget about that. Even that is not true (why?).
>>
>
> Because it would never be called. Basically, what you'd need is this=20
> constructor:
>
> template<size_t N>
> string_view(const char s[N]);
>
> But you already have this constructor:
>
> string_view(const char *s);
>
> An array decays into a pointer. And since the pointer constructor is not =
a=20
> template, it is considered a better match than the array version. And=20
> therefore, any ltieral you pass will go through the pointer version rathe=
r=20
> than the array template.
>
> And it should be noted that this has nothing to do with being a literal.=
=20
> If you used a `const char[]` variable, it *still* would prefer the=20
> pointer version due to array->pointer conversion. So this is not a case o=
f=20
> "string literals are broken now".
>

How can you say that preferring a lossy conversion over a lossless one is=
=20
not broken? (Here, we lose the length information)
This make it impossible to work with string literal because they simply=20
don't exist in the language. This is why I said string literals are broken.
=20

>
> But there's no "fix" for this, since any array->pointer "fix" would be=20
> both wildly incompatible with C and break tons and tons of code. So you c=
an=20
> either accept the language and work with what we have, or rail against it=
..
>


Ok it's not possible to fix array decay because of backward compatibility,=
=20
but it is still possible to fix string literals if we make them something=
=20
that is not an array.
So I rail against those defects in order to be heard, and maybe, at some=20
point, they will be fixed.
If this is not the place to speak out loud about those defects, then where=
=20
should we go?

But don't get me wrong, when I code, I work with what I have, and I accept=
=20
the language as it is.
=20

>
> It's funny how the more I dig in C++, the more bulky it appears to be jus=
t=20
>> because of these very small annoyances.
>> =20
>>
>>>
>>> It's a 3 step process; let's not interfere in that.
>>> =20
>>>
>>>> We could have exatcly the situation with string interpolation:
>>>> auto s =3D std::concat(F"{str1}{str2}{str3}");
>>>> // would be equivalent to
>>>> auto s =3D F"{str1}{str2}{str3}"s;
>>>>
>>>> I don't see why allowing UDL to work like that would decrease usabilit=
y=20
>>>> as we could always use regular functions.
>>>>
>>>
>>> Because you can't do this:
>>>
>>> std::concat(F"some string {variable} other string"sv);
>>>
>>> Under my system, the UDL employed here allows you to decide how to=20
>>> process each of the literal fragments. The UDL applies to the parts of =
the=20
>>> literal that are actually strings. So `concat` would get `string_view`s=
,=20
>>> rather than `const char[X]` parameters.
>>>
>>> Under your system, the processing of the literal fragments is controlle=
d=20
>>> entirely by the system that computes the aggregation.
>>>
>>
>> Let's sum up, string literals are broken today. So we should probably tr=
y=20
>> to solve this big issue before trying to see how we can cripple=20
>> string_interpolation in order to fit in current-ish C++.
>>
>
> I fail to see why applying a UDL to the literal fragments rather than the=
=20
> interpolation aggregation operation should be considered "crippling" stri=
ng=20
> interpolation.
>
> Whatever breakage you see in literals isn't standing in the way of string=
=20
> interpolation. It's just standing in the way of string interpolation=20
> working the way *you* want it to.
>

Because string interpolation is dealing with string literals, if those=20
literals are broken (and they are), how can we have a proper string=20
interpolation?

You said:

> The point of that discussion was a comment someone made about doing=20
> template metaprogramming on string literals. To do that, you need a way t=
o=20
> access each literal as a distinct type, some `string_literal<char, 'c',=
=20
> 'h', 'a', 'r'>` type. And only a UDL applied to each fragment can perform=
=20
> that kind of synthesis.
>

UDL is the only way to do it only because string literals are broken. If we=
=20
had proper string literals, it should be possible to do it simply with=20
regular functions.
So even with your approach, broken string literals are a problem for string=
=20
interpolation. Just not at the same place.

I'm not sure if my approach is the right one (it's probably not), but most=
=20
of your arguments stand only because string literal are broken (otherwise,=
=20
it would have been simple to do the same with my approach too).

My point is: yes your approach makes it easier with current C++, but we=20
shouldn't go for something that works quite well with current C++, but=20
something that will work very well with future C++.
That's why I think it's better to first fix string literals. And then have=
=20
string interpolation right the first time.

And btw, if string literals are fixed, string interpolation could be made a=
=20
library solution only ( with a different but reasonable syntax).

PS: I think it would be preferable to stop the discussion here, as it=20
becomes more and more off-topic.

--=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/3468ee0c-a44a-437a-a835-0156c623df2e%40isocpp.or=
g.

------=_Part_11924_21200749.1518542339406
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><br>Le mardi 13 f=C3=A9vrier 2018 17:35:49 UTC+1, Nico=
l Bolas a =C3=A9crit=C2=A0:<blockquote class=3D"gmail_quote" style=3D"margi=
n: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><di=
v dir=3D"ltr">On Tuesday, February 13, 2018 at 4:50:00 AM UTC-5, <a>floria.=
...@gmail.com</a> wrote:<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">Le mardi 13 f=C3=A9vrier 2018 07:28:45 UTC+1, Nicol Bolas a =C3=A9crit=
=C2=A0:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8e=
x;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">On Monday, =
February 12, 2018 at 4:08:37 PM UTC-5, <a>floria...@gmail.com</a> wrote:<bl=
ockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-l=
eft:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">Le lundi 12 f=C3=A9vr=
ier 2018 21:11:14 UTC+1, Nicol Bolas a =C3=A9crit=C2=A0:<blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><div dir=3D"ltr">On Monday, February 12, 2018 at 12:=
43:41 PM UTC-5, <a>floria...@gmail.com</a> wrote:<blockquote class=3D"gmail=
_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padd=
ing-left:1ex"><div dir=3D"ltr">Le lundi 12 f=C3=A9vrier 2018 17:56:48 UTC+1=
, Nicol Bolas a =C3=A9crit=C2=A0:<blockquote class=3D"gmail_quote" style=3D=
"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><d=
iv dir=3D"ltr">On Monday, February 12, 2018 at 11:15:33 AM UTC-5, <a>floria=
....@gmail.com</a> wrote:</div></blockquote><blockquote class=3D"gmail_quote=
" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-le=
ft:1ex"><div dir=3D"ltr"><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> </div><blockquote class=3D"gmail_quote" style=3D"margin:0;ma=
rgin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"lt=
r"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;bo=
rder-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>With that =
in mind, the implementation of your concat function 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 could also use std::apply.<br=
></div></div></blockquote><div><br>You cannot `apply` things to operators. =
Not without creating a lambda function that gets called with it.<br></div><=
/div></blockquote><div>=C2=A0</div><div>Why not? You can get the address of=
 an operator, and this is a callable object.</div></div></blockquote><div><=
br>You can only get the address of a single overload of an operator. Rememb=
er: the whole idea is that you&#39;re dealing with a sequence of variables =
of different types. So the second parameter to the operator has to be of di=
fferent types for different invocations of the operator.<br></div></div></b=
lockquote><div><br></div><div>This is another quirk of C++ that should be f=
ixed.<br></div></div></blockquote><div><br>Which incidentally is yet anothe=
r proposal (lifting lambdas) that stalled.<br><br></div><blockquote class=
=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc s=
olid;padding-left:1ex"><div dir=3D"ltr"><div></div><blockquote class=3D"gma=
il_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;pa=
dding-left:1ex"><div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D=
"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><d=
iv dir=3D"ltr"><div></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>The fact is, it&#39;s a <i>lot</i> easier in C++ as it curren=
tly stands to go from parameter pack of values to an object than it is to g=
o from an object to a parameter pack of values. I wish that were not the ca=
se, but so long as it is the case, parameter packs will remain the easier-t=
o-use option.<br></div></div></blockquote><div>=C2=A0</div><div>You have a =
point. <br></div><div><br></div><blockquote class=3D"gmail_quote" style=3D"=
margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><di=
v dir=3D"ltr"><div><br></div><blockquote class=3D"gmail_quote" style=3D"mar=
gin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div d=
ir=3D"ltr"><div></div><div></div>UDL the aggregate is not important to me, =
but it was easy to include and allows neat syntax (in my opinion).<br></div=
></blockquote><div><br>But it makes it impossible to apply a UDL to the str=
ing fragments. And that&#39;s important if you do want to use template meta=
programming on string literals.<br></div></div></blockquote><div><br></div>=
<div>I&#39;m not sure to see the use case here. When you use UDL, you want =
the whole literal to be what you say it would be.</div><div><div style=3D"b=
ackground-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><=
span style=3D"color:#000"> s </span><span style=3D"color:#660">=3D</span><s=
pan style=3D"color:#000"> </span><span style=3D"color:#080">&quot;something=
&quot;</span><span style=3D"color:#000">s</span><span style=3D"color:#660">=
;</span><span style=3D"color:#000"> </span><span style=3D"color:#800">// s =
is a string</span><span style=3D"color:#000"><br></span><span style=3D"colo=
r:#008">auto</span><span style=3D"color:#000"> sv </span><span style=3D"col=
or:#660">=3D</span><span style=3D"color:#000"> </span><span style=3D"color:=
#080">&quot;some other&quot;</span><span style=3D"color:#000">sv</span><spa=
n style=3D"color:#660">;</span><span style=3D"color:#000"> </span><span sty=
le=3D"color:#800">// s is a string view</span><span style=3D"color:#000"><b=
r></span></div></code></div>We are not interested in what is happening in t=
he middle. I don&#39;t why it should be different with string interpolation=
 (or whatever the name is).<br></div></div></blockquote><div><br>Because no=
t all of the &quot;literal&quot; is actually a literal anymore. That&#39;s =
the whole point of string interpolation: you&#39;re taking a literal and yo=
u&#39;re augmenting it with some non-literal data. Potentially <i>runtime</=
i> non-literal data. It isn&#39;t a literal anymore, so the UDL suffix can&=
#39;t apply to the aggregate. It can only apply to the individual literal f=
ragments of the string.<br></div></div></blockquote><div><br></div><div>Her=
e, I don&#39;t care if it&#39;s called a literal, or if we invent a new nam=
e for this concept that appeared to match the concept of literal when &quot=
;string interpolation&quot; was not a thing.</div><div>I&#39;m more interes=
ted in the final syntax as the end user will see it.</div><div><br></div><d=
iv>And I would prefer concatenate like this:</div><div><div style=3D"backgr=
ound-color:rgb(250,250,250);border-color:rgb(187,187,187);border-style:soli=
d;border-width:1px"><code><div><span style=3D"color:#008">auto</span><span =
style=3D"color:#000"> s </span><span style=3D"color:#660">=3D</span><span s=
tyle=3D"color:#000"> F</span><span style=3D"color:#080">&quot;{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></div></code></div></div=
><div>than this:</div><div><div style=3D"background-color:rgb(250,250,250);=
border-color:rgb(187,187,187);border-style:solid;border-width:1px"><code><d=
iv><span style=3D"color:#008">auto</span><span style=3D"color:#000"> s </sp=
an><span style=3D"color:#660">=3D</span><span style=3D"color:#000"> std</sp=
an><span style=3D"color:#660">::</span><span style=3D"color:#000">concat</s=
pan><span style=3D"color:#660">(</span><span style=3D"color:#000">F</span><=
span style=3D"color:#080">&quot;{str1}{str2}{<wbr>str3}&quot;</span><span s=
tyle=3D"color:#660">);</span><span style=3D"color:#000"><br></span></div></=
code></div><br>The first one looks more natural in my opinion.<br></div></d=
iv></blockquote><div><br>It only looks more natural for the trivial cases. =
Consider what `std::concat` would look like. It creates an `ostringstream`,=
 applies it to each parameter, and moves its result out. Why pick `ostrings=
tream`? Why not allow the user to decide which kind of stream to use and th=
erefore which resulting string type to build?<br></div></div></blockquote><=
div><br></div><div>I never said this should work only with UDL. I just said=
 that I think it is more natural if UDL worked like that.</div><div>But I r=
eally think the user should keep control over what can be done with this sy=
ntax.</div><div>So I totally agree with you: users should be able to call t=
heir own functions with it.</div><div><br></div><div>And then, even conside=
ring F&quot;{str1}{str2}{str3}&quot;s for concatenating, I never mentionned=
 std::ostringstream, I just said converted into an efficient way of concate=
nating strings.</div><div>In that case, I just considered that when we use =
operator &quot;&quot;s, we want a std::string.<br></div></div></blockquote>=
<div><br>You say that the literal `s` means you want a `std::string`. But t=
hat&#39;s not enough information, because you now have to define how to <i>=
get</i> a `std::string` from values that aren&#39;t `std::string`. That&#39=
;s why you need more information than a mere literal can provide.<br><br>Th=
ere are many ways to get a std::string from an interpolated string. Your `o=
perator&quot;&quot;s` will only be doing one of them. That mechanism will b=
e <i>fixed</i>. Inflexible. Unchangeable.<br></div></div></blockquote><div>=
<br></div><div>I never said here the this operator &quot;&quot;s should wor=
k with this: F&quot;foo {5} bar&quot;s... To be fair, I have been thinking =
this should work only if every single part is convertible to std::string. S=
o the result is unambiguous, so it doesn&#39;t matter if it is fixed, uncha=
ngeable.</div><div>And if you want a function call, do a function call, it =
will work.<br></div><div>=C2=A0</div><blockquote class=3D"gmail_quote" styl=
e=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex=
"><div dir=3D"ltr"><div><br>That&#39;s bad. A function call will be more ve=
rsatile.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0;m=
argin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"l=
tr"><div></div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-l=
eft:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><di=
v>You can&#39;t do that with a UDL; they can&#39;t take an extra template p=
arameter. `std::concat` can.<br></div></div></blockquote><div><br></div><di=
v>To do that, just use a function. We can have multiple syntaxes to do the =
same thing.</div><div>The closest example I can think of is:</div><div><div=
 style=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);b=
order-style:solid;border-width:1px"><code><div><span style=3D"color:#008">a=
uto</span><span style=3D"color:#000"> s </span><span style=3D"color:#660">=
=3D</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"=
>(</span><span style=3D"color:#080">&quot;str&quot;</span><span style=3D"co=
lor:#660">);</span><span style=3D"color:#000"><br></span><span style=3D"col=
or:#800">// is equivalent to</span><span style=3D"color:#000"><br></span><s=
pan style=3D"color:#008">auto</span><span style=3D"color:#000"> s </span><s=
pan style=3D"color:#660">=3D</span><span style=3D"color:#000"> </span><span=
 style=3D"color:#080">&quot;str&quot;</span><span style=3D"color:#000">s</s=
pan><span style=3D"color:#660">;</span><span style=3D"color:#000"><br></spa=
n></div></code></div></div><div><br></div></div></blockquote><div><br>No, i=
t&#39;s not:<br><br><div style=3D"background-color:rgb(250,250,250);border-=
color:rgb(187,187,187);border-style:solid;border-width:1px"><code><div><spa=
n style=3D"color:#008">auto</span><span style=3D"color:#000"> s1 </span><sp=
an style=3D"color:#660">=3D</span><span style=3D"color:#000"> std</span><sp=
an style=3D"color:#660">::</span><span style=3D"color:#008">string</span><s=
pan style=3D"color:#660">(</span><span style=3D"color:#080">&quot;str\0str&=
quot;</span><span style=3D"color:#660">);</span><span style=3D"color:#000">=
<br></span><span style=3D"color:#008">auto</span><span style=3D"color:#000"=
> s2 </span><span style=3D"color:#660">=3D</span><span style=3D"color:#000"=
> </span><span style=3D"color:#080">&quot;str\0str&quot;</span><span style=
=3D"color:#000">s</span><span style=3D"color:#660">;</span></div></code></d=
iv><br>In `s1` the constructor has to do `char_traits&lt;char&gt;::length` =
to compute the number of characters in the string. That will terminate the =
string at the first NUL character. In the second case, the UDL gets the siz=
e from the literal parameter directly.<br><br>Things like this are why it i=
s important to separate literal operations from string interpolation. So th=
at UDLs can do the job they exist to do (literal synthesis) and string inte=
rpolation can do the job its meant to do (breaking down literals into seque=
nces of values). And the aggregation can do the job its meant to do (take s=
equences of values and act on them).<br></div></div></blockquote><div><br><=
/div><div>String literals are broken now. This is not fixable by UDL curren=
tly. So all in all, we are doomed here.</div></div></blockquote><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>If you write a function =
that need to take std::string_view for literal parts, let&#39;s do that, yo=
u don&#39;t need to force the literal to be a string_view to work, as they =
are implicitly convertible from const char[]&amp;. The same with std::strin=
g.</div><div>No, forget about that. Even that is not true (why?).</div></di=
v></blockquote><div><br>Because it would never be called. Basically, what y=
ou&#39;d need is this constructor:<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">template</span><span style=3D"=
color:#660">&lt;</span><span style=3D"color:#000">size_t N</span><span styl=
e=3D"color:#660">&gt;</span><span style=3D"color:#000"><br>string_view</spa=
n><span style=3D"color:#660">(</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:#000"> s</span><span style=3D"color:#660">[</span><span=
 style=3D"color:#000">N</span><span style=3D"color:#660">]);</span></div></=
code></div><br>But you already have this constructor:<br><br><div style=3D"=
background-color:rgb(250,250,250);border-color:rgb(187,187,187);border-styl=
e:solid;border-width:1px"><code><div><span style=3D"color:#000">string_view=
</span><span style=3D"color:#660">(</span><span style=3D"color:#008">const<=
/span><span style=3D"color:#000"> </span><span style=3D"color:#008">char</s=
pan><span style=3D"color:#000"> </span><span style=3D"color:#660">*</span><=
span style=3D"color:#000">s</span><span style=3D"color:#660">);</span></div=
></code></div><br>An array decays into a pointer. And since the pointer con=
structor is not a template, it is considered a better match than the array =
version. And therefore, any ltieral you pass will go through the pointer ve=
rsion rather than the array template.<br><br>And it should be noted that th=
is has nothing to do with being a literal. If you used a `const char[]` var=
iable, it <i>still</i> would prefer the pointer version due to array-&gt;po=
inter conversion. So this is not a case of &quot;string literals are broken=
 now&quot;.<br></div></div></blockquote><div><br></div><div>How can you say=
 that preferring a lossy conversion over a lossless one is not broken? (Her=
e, we lose the length information)<br></div><div>This make it impossible to=
 work with string literal because they simply don&#39;t exist in the langua=
ge. This is why I said string literals are broken.</div><div>=C2=A0</div><b=
lockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;borde=
r-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><br>But th=
ere&#39;s no &quot;fix&quot; for this, since any array-&gt;pointer &quot;fi=
x&quot; would be both wildly incompatible with C and break tons and tons of=
 code. So you can either accept the language and work with what we have, or=
 rail against it.<br></div></div></blockquote><div><br></div><div><div><br>=
</div>Ok it&#39;s not possible to fix array decay because of=20
backward compatibility, but it is still possible to fix string literals=20
if we make them something that is not an array.</div><div>So I rail against=
 those defects in order to be heard, and maybe, at some point, they will be=
 fixed.</div><div>If this is not the place to speak out loud about those de=
fects, then where should we go?<br></div><div><br></div><div>But don&#39;t =
get me wrong, when I code, I work with what I have, and I accept the langua=
ge as it is.<br></div><div>=C2=A0</div><blockquote class=3D"gmail_quote" st=
yle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-lef=
t: 1ex;"><div dir=3D"ltr"><div><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>It&#39;s funny how the more I dig in C++, the m=
ore bulky it appears to be just because of these very small annoyances.<br>=
</div><div>=C2=A0</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><br>It&#39;s a 3 step process; let&#39;s not interfere in that.<b=
r>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-le=
ft:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div=
></div><div>We could have exatcly the situation with string interpolation:<=
/div><div><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:#008">auto</span><span style=3D"color:#000"> s </span><span style=3D=
"color:#660">=3D</span><span style=3D"color:#000"> std</span><span style=3D=
"color:#660">::</span><span style=3D"color:#000">concat</span><span style=
=3D"color:#660">(</span><span style=3D"color:#000">F</span><span style=3D"c=
olor:#080">&quot;{str1}{str2}{<wbr>str3}&quot;</span><span style=3D"color:#=
660">);</span><span style=3D"color:#000"><br></span><span style=3D"color:#8=
00">// would be equivalent to</span><span style=3D"color:#000"><br></span><=
span style=3D"color:#008">auto</span><span style=3D"color:#000"> s </span><=
span style=3D"color:#660">=3D</span><span style=3D"color:#000"> F</span><sp=
an style=3D"color:#080">&quot;{str1}{str2}{str3}&quot;</span><span style=3D=
"color:#000">s</span><span style=3D"color:#660">;</span><span style=3D"colo=
r:#000"><br></span></div></code></div><br>I don&#39;t see why allowing UDL =
to work like that would decrease usability as we could always use regular f=
unctions.<br></div></div></blockquote><div><br>Because you can&#39;t do thi=
s:<br><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">::</span><span style=3D"c=
olor:#000">concat</span><span style=3D"color:#660">(</span><span style=3D"c=
olor:#000">F</span><span style=3D"color:#080">&quot;some string {variable} =
other string&quot;</span><span style=3D"color:#000">sv</span><span style=3D=
"color:#660">);</span></div></code></div><br>Under my system, the UDL emplo=
yed here allows you to decide how to process each of the literal fragments.=
 The UDL applies to the parts of the literal that are actually strings. So =
`concat` would get `string_view`s, rather than `const char[X]` parameters.<=
br><br>Under your system, the processing of the literal fragments is contro=
lled entirely by the system that computes the aggregation.</div></div></blo=
ckquote><div><br></div><div>Let&#39;s sum up, string literals are broken to=
day. So we should probably try to solve this big issue before trying to see=
 how we can cripple string_interpolation in order to fit in current-ish C++=
..<br></div></div></blockquote><div><br>I fail to see why applying a UDL to =
the literal fragments rather than the interpolation aggregation operation s=
hould be considered &quot;crippling&quot; string interpolation.<br><br>What=
ever breakage you see in literals isn&#39;t standing in the way of string i=
nterpolation. It&#39;s just standing in the way of string interpolation wor=
king the way <i>you</i> want it to.<br></div></div></blockquote><div><br></=
div><div>Because string interpolation is dealing with string literals, if t=
hose literals are broken (and they are), how can we have a proper string in=
terpolation?</div><div><br></div><div>You said:</div><blockquote class=3D"g=
mail_quote" style=3D"margin: 0px 0px 0px 0.8ex; border-left: 1px solid rgb(=
204, 204, 204); padding-left: 1ex;"><div>The point of that discussion was a=
 comment someone made about doing=20
template metaprogramming on string literals. To do that, you need a way=20
to access each literal as a distinct type, some `string_literal&lt;char,
 &#39;c&#39;, &#39;h&#39;, &#39;a&#39;, &#39;r&#39;&gt;` type. And only a U=
DL applied to each fragment=20
can perform that kind of synthesis.</div></blockquote><div><br></div><div>U=
DL is the only way to do it only because string literals are broken. If we =
had proper string literals, it should be possible to do it simply with regu=
lar functions.</div><div>So even with your approach, broken string literals=
 are a problem for string interpolation. Just not at the same place.</div><=
div><br></div><div>I&#39;m not sure if my approach is the right one (it&#39=
;s probably not), but most of your arguments stand only because string lite=
ral are broken (otherwise, it would have been simple to do the same with my=
 approach too).</div><div><br></div><div>My point is: yes your approach mak=
es it easier with current C++, but we shouldn&#39;t go for something that w=
orks quite well with current C++, but something that will work very well wi=
th future C++.</div><div>That&#39;s why I think it&#39;s better to first fi=
x string literals. And then have string interpolation right the first time.=
<br></div><div><br></div><div>And btw, if string literals are fixed, string=
 interpolation could be made a library solution only ( with a different but=
 reasonable syntax).</div><div><br></div><div>PS: I think it would be prefe=
rable to stop the discussion here, as it becomes more and more off-topic.<b=
r></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/3468ee0c-a44a-437a-a835-0156c623df2e%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/3468ee0c-a44a-437a-a835-0156c623df2e=
%40isocpp.org</a>.<br />

------=_Part_11924_21200749.1518542339406--

------=_Part_11923_890054300.1518542339405--

.
