<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div>On Sat, Apr 6, 2019 at 7:43 PM Alexander Us <<a href="mailto:coillol@yandex.ru">coillol@yandex.ru</a>> wrote: <br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div>06.04.2019, 19:36, "Arthur O'Dwyer" <<a href="mailto:arthur.j.odwyer@gmail.com" target="_blank">arthur.j.odwyer@gmail.com</a>>:</div><blockquote type="cite"><div>On Fri, Apr 5, 2019 at 7:46 PM Alexander Us via cfe-dev <<a rel="noopener noreferrer" href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>> wrote:</div><div><blockquote style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><br></blockquote><blockquote style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div>1) First question is about variadic templates and how they are expanded. Consider the following code:<br><br><span style="font-family:"andale mono",times">template<typename A> struct S {};<br><br>template<typename T, typename...Rest><br>using U = S<T, Rest...>; // is it valid?<br><br>using SI = U<int>; // seems, that there should be S<int> and there is nothing ill-formed</span><br><br>The problem here is that only gcc (starting from version 7.1) is able to compile this code. Other compilers report that using directive is ill-formed because it provides too many template parameters for S. Who is right in this case?</div></blockquote><div> </div><div>My understanding is that all four compilers' behavior is correct. Template `U` is well-formed <strong><em>only </em></strong>when Rest... is an empty pack, and thus the program is ill-formed (no diagnostic required) via <a rel="noopener noreferrer" href="http://eel.is/c++draft/temp.res#8.3" target="_blank">http://eel.is/c++draft/temp.res#8.3</a>.  So technically any behavior at all is conforming to the standard. (This doesn't mean the compiler's behavior couldn't be made more user-friendly! An enhancement request might still be warranted.)</div><div> </div><blockquote style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div>2) Second example is quite more complicated. The code is:<br><br><span style="font-family:"andale mono",times">template<typename A, typename B> struct S {};<br><br>template<template<typename...> typename F><br>struct Flip {<br>  template<typename A, typename B, typename...Rest><br>  using Type = F<B, A, Rest...>;<br>};<br><br>template<template<typename...> typename F, typename...Args><br>struct PartialApply {<br>  template<typename...Rest><br>  using Type = F<Args..., Rest...>;<br>};<br><br>using X = typename PartialApply<Flip<S>::Type, int>::template Type<bool>; // there should be S<bool, int></span><br><br>Now this can be compiled only by icc. Other compilers become mad and start to report very strange error. For example, gcc says that there is "pack expansion of 'B'" in Flip. clang and msvc produce similar error. Is this code valid C++ after all?</div></blockquote><div> </div><div>Well, same as above: the template `Flip<S>::Type` is invalid and thus causes the <em>entire program</em> to be ill-formed, no diagnostic required.</div></div></blockquote><div> </div><div>Okay, it really seems that Flip is ill-formed. But changing Flip in the second example to:<br><br><span style="font-family:"andale mono",times">template<template<typename, typename> typename F><br>struct Flip {<br>  template<typename A, typename B><br>  using Type = F<B, A>;<br>};</span><br><br>actually doesn't fix compilers. They're still saying that the program is incorrect because of this mystical pack expansion of 'B'. I assume that now it is a bug.</div></blockquote><div><br></div><div>Sadly, no.  The culprit this time is that `Flip<S>::Type` is an alias template, and the status quo as of C++17 is that it is specifically forbidden to expand a parameter pack into the template argument list of an alias template.</div><div><div>Here is a Godbolt illustrating the difference in what's supported for alias templates versus class templates: <a href="https://godbolt.org/z/YAzHMc">https://godbolt.org/z/YAzHMc</a></div></div><div><br></div><div>This is <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1430">CWG open issue 1430</a>. Implementors seem to agree that mixing parameter packs and aliases is troublesome for them. Clang's code-comments on CWG1430 talk about "canonicalization," which I think means "asking whether two template declarations declare the same template or different templates."</div><div>Example: <a href="https://godbolt.org/z/C9Qiwd">https://godbolt.org/z/C9Qiwd </a></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><blockquote type="cite"><div><div><div><div><div><div><blockquote style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div>Also if write similar code but in context of lambdas all compilers will work as expected. Does processing of variadic lambdas differ from processing of variadic templates?</div></blockquote><div> </div><div>You'd have to show an example. </div></div></div></div></div></div></div></blockquote><div><span style="font-family:"andale mono",times">auto fvar = [](auto f) {<br>  return [f](auto a, auto...rest) { return f(a, rest...); };<br>};<br><br>auto sqr = [](auto a) { return a * a; };</span><br> </div><div><span style="font-family:"andale mono",times">auto foo() {<br>  return fvar(sqr)(2); // works fine<br>}</span><br></div></blockquote><div><br></div><div>Written out in C++03, we have</div><div><a href="https://godbolt.org/z/eJ97M2">https://godbolt.org/z/eJ97M2</a></div><div>The problematic template is FRet<Sqr>::call. However, since that template is itself generated <i>from </i>a template, the compiler would have to do extra work to check it "prior to any instantiation" under <a href="http://eel.is/c++draft/temp.res#8">http://eel.is/c++draft/temp.res#8</a> — and so the compiler just doesn't do that (optional) check, and so the code appears to work.<br></div><div>My understanding is that the template FRet<Sqr>::call (i.e. `decltype(fvar(sqr))::operator()`) is just as ill-formed as your original template `U` from example number one, and so this code does have undefined behavior. However, I believe it's perfectly safe to use this code in practice.</div><div>The major difference between this code and your original example number one is that in this one the ill-formed template is created by template argument substitution — it's not "visible" to the compiler prior to substituting things into dependent expressions. Example: <a href="https://godbolt.org/z/LZvWhA">https://godbolt.org/z/LZvWhA</a>  And the major difference between this code and your example number two is that this one doesn't involve alias templates.</div><div><br></div><div>–Arthur</div></div></div></div></div></div></div></div></div></div></div></div></div></div>