[cfe-dev] Questions about templates and different behavior of 4 different front-ends

Arthur O'Dwyer via cfe-dev cfe-dev at lists.llvm.org
Sat Apr 6 09:36:37 PDT 2019


On Fri, Apr 5, 2019 at 7:46 PM Alexander Us via cfe-dev <
cfe-dev at lists.llvm.org> wrote:

> Hi,
>
> While experimenting with some heavily templated code I have faced with
> some problems. First of all, I do not understand whether my code should be
> compiled at all (because of processing of trailing parameters packs) and I
> have found nothing about it in C++17 standard draft. I tried 4 different
> compilers (with different front-ends) on godbolt: gcc, clang, icc, msvc.
>

This seems like a question that would be more suited to posting on the
cpplang Slack or StackOverflow, rather than cfe-dev specifically (since it
has nothing directly to do with the Clang front-end but is a question about
C++ in general).
However...


> 1) First question is about variadic templates and how they are expanded.
> Consider the following code:
>
> template<typename A> struct S {};
>
> template<typename T, typename...Rest>
> using U = S<T, Rest...>; // is it valid?
>
> using SI = U<int>; // seems, that there should be S<int> and there is
> nothing ill-formed
>
> 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?
>

My understanding is that all four compilers' behavior is correct. Template
`U` is well-formed *only *when Rest... is an empty pack, and thus the
program is ill-formed (no diagnostic required) via
http://eel.is/c++draft/temp.res#8.3.  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.)


> 2) Second example is quite more complicated. The code is:
>
> template<typename A, typename B> struct S {};
>
> template<template<typename...> typename F>
> struct Flip {
>   template<typename A, typename B, typename...Rest>
>   using Type = F<B, A, Rest...>;
> };
>
> template<template<typename...> typename F, typename...Args>
> struct PartialApply {
>   template<typename...Rest>
>   using Type = F<Args..., Rest...>;
> };
>
> using X = typename PartialApply<Flip<S>::Type, int>::template Type<bool>;
> // there should be S<bool, int>
>
> 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?
>

Well, same as above: the template `Flip<S>::Type` is invalid and thus
causes the *entire program* to be ill-formed, no diagnostic required.

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?
>

You'd have to show an example.

For more on the wacky Wild West situation around interchangeability of pack
and non-pack template parameters, see the later sections of
https://quuxplusone.github.io/blog/2019/01/20/covariance-and-contravariance/

–Arthur
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20190406/9481a1c6/attachment.html>


More information about the cfe-dev mailing list