Topic: initializer_list generalization


Author: Ramkumar Ramachandra <artagnon@gmail.com>
Date: Tue, 29 May 2018 21:23:17 -0700
Raw View
--00000000000032561b056d64b892
Content-Type: text/plain; charset="UTF-8"

Hi folks,

I faced more than a few issues with initializer_lists, especially nested
ones. Clang tip on C++17 doesn't infer types from initializer lists, and I
have to keep repeating myself in the type and value template parameters.
This leads to overtly ugly and verbose code, especially when trying to
create a huge number of compile-time tables using constexpr. The best
standard-library tool we have for using constexpr is std::array, since
operator[] is constexpr -- so, we can operate on std::arrays at
compile-time with great ease. However, there are older abstractions like
std::pair (part of utility), which cannot be used in a constexpr context
easily. This is what I have today:

template <typename T, std::size_t N1, std::size_t N2>
constexpr std::array<T, N1 + N2> operator+(std::array<T, N1> A1,
std::array<T, N2> A2) {
  std::array<T, N1 + N2> Ret{};
  std::size_t i = 0;
  for (; i < N1; ++i) {
    Ret[i] = A1[i];
  }
  for (; i < N2; ++i) {
    Ret[N1 + i] = A2[i];
  }
  return Ret;
}

Very straightforward way to combine two std::arrays at compile-time, with
the small ugliness of std::array not having a default-constructor,
necessitating the use of a vacuous `{}`. Since I nested a std::pair within
the std::array, I had to define a new operator= for it:

template <typename T, typename Q> struct pwrapper {
  T first;
  Q second;
  constexpr pwrapper() = default;
  constexpr pwrapper(T f, Q s) : first(f), second(s) {}
  constexpr pwrapper<T, Q> operator=(pwrapper<T, Q> Other) {
    first = Other.first;
    second = Other.second;
    return *this;
  }
};

What are the default constructors for T and Q? I don't know. Do I need to
guard it with a std::enable_if? These are open-ended questions.

Okay, so back to the initializer_list "proxy object" that we have today
that works in some special-case "examples", and doesn't generalize:

  static constexpr OpMaskActions<std::size(SequentialSzActions), 1>
GEPActions1 =
      std::array<std::tuple<unsigned, unsigned,
SzActions<std::size(SequentialSzActions)>>, 1>{
          std::tuple<unsigned, unsigned,
SzActions<std::size(SequentialSzActions)>>{
              V_GEP, OpIdxMask::Primary, SequentialSzActions}};

Terribly ugly, because I had to repeat SequentialSzActions three times, I
had to repeat the template parameter '1' twice, and even the tuple type is
repeated over and over again. Why can't I use `using`? Because `using`
cannot be templatized -- another problem. We would ideally like to be able
to do this:

  static constexpr OpMaskActions<std::size(SequentialSzActions), 1>
GEPActions1 =
      {{V_GEP, OpIdxMask::Primary, SequentialSzActions}};

.... and Clang should infer the rest. Okay, let's dig deeper and see what
OpMaskActions is:

template <std::size_t N1, std::size_t N2> class OpMaskActions {
  using OpMaskAction = std::tuple<unsigned, unsigned, SzActions<N1>>;
  std::array<OpMaskAction, N2> Data;

public:
  constexpr OpMaskActions(std::array<OpMaskAction, N2> D) : Data(D) {}
  constexpr const SzActions<N1> &operator[](std::size_t Pos) noexcept {
return Data[Pos]; }
  constexpr auto size() const { return Data.size(); }
  constexpr OpMaskActions operator+(const OpMaskActions &Other) const {
return Data + Other.Data; }
};

Obviously, we can't use the name OpMaskAction outside the class itself. Why
did we have to create OpMaskAction in the first place, and not use
std::array instead? Because the type would have been very verbose, and I
wanted to hide it behind an abstraction -- create an operator+, operator[],
and size() that forwards to the previous std::array constexpr equivalents.
Ideally, we'd like the '1' in the previous example gone, but it would
require some kind of partial template inference that we have no concept of
today -- TS std::experimental::make_array()

auto arr = std::experimental::make_array(...);

.... but `auto` is again "special", and cannot be used with `static
constexpr`. Back to the same problems -- either have possibly buggy runtime
code with full-power or bend over backwards to have compile-time tables
that don't crash at all.

Warm regards.

--
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 email 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/CALkWK0n4rzL9SCCBcQa0De7Nsd8OBG8W7yDdo8Nai_0KTS%3D9jw%40mail.gmail.com.

--00000000000032561b056d64b892
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Hi folks,<div><br></div><div>I faced more than a few issue=
s with initializer_lists, especially nested ones. Clang tip on C++17 doesn&=
#39;t infer types from initializer lists, and I have to keep repeating myse=
lf in the type and value template parameters. This leads to overtly ugly an=
d verbose code, especially when trying to create a huge number of compile-t=
ime tables using constexpr. The best standard-library tool we have for usin=
g constexpr is std::array, since operator[] is constexpr -- so, we can oper=
ate on std::arrays at compile-time with great ease. However, there are olde=
r abstractions like std::pair (part of utility), which cannot be used in a =
constexpr context easily. This is what I have today:</div><div><br></div><d=
iv><div><font face=3D"monospace, monospace">template &lt;typename T, std::s=
ize_t N1, std::size_t N2&gt;</font></div><div><font face=3D"monospace, mono=
space">constexpr std::array&lt;T, N1 + N2&gt; operator+(std::array&lt;T, N1=
&gt; A1, std::array&lt;T, N2&gt; A2) {</font></div><div><font face=3D"monos=
pace, monospace">=C2=A0 std::array&lt;T, N1 + N2&gt; Ret{};</font></div><di=
v><font face=3D"monospace, monospace">=C2=A0 std::size_t i =3D 0;</font></d=
iv><div><font face=3D"monospace, monospace">=C2=A0 for (; i &lt; N1; ++i) {=
</font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 Ret[i] =
=3D A1[i];</font></div><div><font face=3D"monospace, monospace">=C2=A0 }</f=
ont></div><div><font face=3D"monospace, monospace">=C2=A0 for (; i &lt; N2;=
 ++i) {</font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =
Ret[N1 + i] =3D A2[i];</font></div><div><font face=3D"monospace, monospace"=
>=C2=A0 }</font></div><div><font face=3D"monospace, monospace">=C2=A0 retur=
n Ret;</font></div><div><font face=3D"monospace, monospace">}</font></div><=
/div><div><br></div><div>Very straightforward way to combine two std::array=
s at compile-time, with the small ugliness of std::array not having a defau=
lt-constructor, necessitating the use of a vacuous `{}`. Since I nested a s=
td::pair within the std::array, I had to define a new operator=3D for it:</=
div><div><br></div><div><div><div><font face=3D"monospace, monospace">templ=
ate &lt;typename T, typename Q&gt; struct pwrapper {</font></div><div><font=
 face=3D"monospace, monospace">=C2=A0 T first;</font></div><div><font face=
=3D"monospace, monospace">=C2=A0 Q second;</font></div><div><font face=3D"m=
onospace, monospace">=C2=A0 constexpr pwrapper() =3D default;</font></div><=
div><font face=3D"monospace, monospace">=C2=A0 constexpr pwrapper(T f, Q s)=
 : first(f), second(s) {}</font></div><div><font face=3D"monospace, monospa=
ce">=C2=A0 constexpr pwrapper&lt;T, Q&gt; operator=3D(pwrapper&lt;T, Q&gt; =
Other) {</font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0=
 first =3D Other.first;</font></div><div><font face=3D"monospace, monospace=
">=C2=A0 =C2=A0 second =3D Other.second;</font></div><div><font face=3D"mon=
ospace, monospace">=C2=A0 =C2=A0 return *this;</font></div><div><font face=
=3D"monospace, monospace">=C2=A0 }</font></div><div><font face=3D"monospace=
, monospace">};</font></div></div></div><div><br></div><div>What are the de=
fault constructors for T and Q? I don&#39;t know. Do I need to guard it wit=
h a std::enable_if? These are open-ended questions.</div><div><br></div><di=
v>Okay, so back to the initializer_list &quot;proxy object&quot; that we ha=
ve today that works in some special-case &quot;examples&quot;, and doesn&#3=
9;t generalize:</div><div><br></div><div><div><font face=3D"monospace, mono=
space">=C2=A0 static constexpr OpMaskActions&lt;std::size(SequentialSzActio=
ns), 1&gt; GEPActions1 =3D</font></div><div><font face=3D"monospace, monosp=
ace">=C2=A0 =C2=A0 =C2=A0 std::array&lt;std::tuple&lt;unsigned, unsigned, S=
zActions&lt;std::size(SequentialSzActions)&gt;&gt;, 1&gt;{</font></div><div=
><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 std=
::tuple&lt;unsigned, unsigned, SzActions&lt;std::size(SequentialSzActions)&=
gt;&gt;{</font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 V_GEP, OpIdxMask::Primary, SequentialSz=
Actions}};</font></div></div><div><br></div><div>Terribly ugly, because I h=
ad to repeat SequentialSzActions three times, I had to repeat the template =
parameter &#39;1&#39; twice, and even the tuple type is repeated over and o=
ver again. Why can&#39;t I use `using`? Because `using` cannot be templatiz=
ed -- another problem. We would ideally like to be able to do this:</div><d=
iv><br></div><div><div><font face=3D"monospace, monospace">=C2=A0 static co=
nstexpr OpMaskActions&lt;std::size(SequentialSzActions), 1&gt; GEPActions1 =
=3D</font></div><div><font face=3D"monospace, monospace">=C2=A0 =C2=A0 =C2=
=A0 {</font><span style=3D"font-family:monospace,monospace">{</span><span s=
tyle=3D"font-family:monospace,monospace">V_GEP, OpIdxMask::Primary, Sequent=
ialSzActions}};</span></div></div><div><font face=3D"monospace, monospace">=
<br></font></div><div><font face=3D"arial, helvetica, sans-serif">... and C=
lang should infer the rest. Okay, let&#39;s dig deeper and see what OpMaskA=
ctions is:</font></div><div><font face=3D"arial, helvetica, sans-serif"><br=
></font></div><div><div><font face=3D"monospace, monospace">template &lt;st=
d::size_t N1, std::size_t N2&gt; class OpMaskActions {</font></div><div><fo=
nt face=3D"monospace, monospace">=C2=A0 using OpMaskAction =3D std::tuple&l=
t;unsigned, unsigned, SzActions&lt;N1&gt;&gt;;</font></div><div><font face=
=3D"monospace, monospace">=C2=A0 std::array&lt;OpMaskAction, N2&gt; Data;</=
font></div><div><font face=3D"monospace, monospace"><br></font></div><div><=
font face=3D"monospace, monospace">public:</font></div><div><span style=3D"=
font-family:monospace,monospace">=C2=A0 constexpr OpMaskActions(std::array&=
lt;OpMaskAction, N2&gt; D) : Data(D) {}</span><br></div><div><font face=3D"=
monospace, monospace">=C2=A0 constexpr const SzActions&lt;N1&gt; &amp;opera=
tor[](std::size_t Pos) noexcept { return Data[Pos]; }</font></div><div><fon=
t face=3D"monospace, monospace">=C2=A0 constexpr auto size() const { return=
 Data.size(); }</font></div><div><font face=3D"monospace, monospace">=C2=A0=
 constexpr OpMaskActions operator+(const OpMaskActions &amp;Other) const { =
return Data + Other.Data; }</font></div><div><font face=3D"monospace, monos=
pace">};</font></div></div><div><br></div><div>Obviously, we can&#39;t use =
the name OpMaskAction outside the class itself. Why did we have to create O=
pMaskAction in the first place, and not use std::array instead? Because the=
 type would have been very verbose, and I wanted to hide it behind an abstr=
action -- create an operator+, operator[], and size() that forwards to the =
previous std::array constexpr equivalents. Ideally, we&#39;d like the &#39;=
1&#39; in the previous example gone, but it would require some kind of part=
ial template inference that we have no concept of today -- TS std::experime=
ntal::make_array()</div><div><br></div><div><font face=3D"monospace, monosp=
ace">auto arr =3D std::experimental::make_array(...);</font></div><div><fon=
t face=3D"monospace, monospace"><br></font></div><div><font face=3D"arial, =
helvetica, sans-serif">... but `auto` is again &quot;special&quot;, and can=
not be used with `static constexpr`. Back to the same problems -- either ha=
ve possibly buggy runtime code with full-power or bend over backwards to ha=
ve compile-time tables that don&#39;t crash at all.</font></div><div><font =
face=3D"arial, helvetica, sans-serif"><br></font></div><div><font face=3D"a=
rial, helvetica, sans-serif">Warm regards.</font></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/CALkWK0n4rzL9SCCBcQa0De7Nsd8OBG8W7yDd=
o8Nai_0KTS%3D9jw%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CALkWK0n4rzL9SC=
CBcQa0De7Nsd8OBG8W7yDdo8Nai_0KTS%3D9jw%40mail.gmail.com</a>.<br />

--00000000000032561b056d64b892--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Tue, 29 May 2018 22:41:56 -0700 (PDT)
Raw View
------=_Part_41901_982676624.1527658916186
Content-Type: multipart/alternative;
 boundary="----=_Part_41902_1708251905.1527658916186"

------=_Part_41902_1708251905.1527658916186
Content-Type: text/plain; charset="UTF-8"

On Wednesday, May 30, 2018 at 12:24:00 AM UTC-4, Ramkumar Ramachandra wrote:
>
> Hi folks,
>
> I faced more than a few issues with initializer_lists, especially nested
> ones.
>


> Clang tip on C++17 doesn't infer types from initializer lists,
>

C++17 class template argument deduction doesn't care if you use parentheses
or braced-init-lists. If Clang didn't get this right, go complain to them.

Overall, it's not clear what you're proposing here. Can you clarify what
exactly you want changed in the language?

--
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 email 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/997f88ac-7137-42aa-ab0e-e058c6c7fffc%40isocpp.org.

------=_Part_41902_1708251905.1527658916186
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Wednesday, May 30, 2018 at 12:24:00 AM UTC-4, Ramkumar =
Ramachandra wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;marg=
in-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"=
ltr">Hi folks,<div><br></div><div>I faced more than a few issues with initi=
alizer_lists, especially nested ones.</div></div></blockquote><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>Clan=
g tip on C++17 doesn&#39;t infer types from initializer lists,</div></div><=
/blockquote><div><br></div><div>C++17 class template argument deduction doe=
sn&#39;t care if you use parentheses or braced-init-lists. If Clang didn&#3=
9;t get this right, go complain to them.<br></div><div><br></div><div>Overa=
ll, it&#39;s not clear what you&#39;re proposing here. Can you clarify what=
 exactly you want changed in the language?<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/997f88ac-7137-42aa-ab0e-e058c6c7fffc%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/997f88ac-7137-42aa-ab0e-e058c6c7fffc=
%40isocpp.org</a>.<br />

------=_Part_41902_1708251905.1527658916186--

------=_Part_41901_982676624.1527658916186--

.