Another "who's right between g++ and clang++?"
This time I'm convinced it's a g++ bug, but I ask for a confirm from standard gurus.
Given the following code
template <template <auto...> class Cnt,
typename ... Types,
Types ... Vals>
void foo (Cnt<Vals...>)
{ }
template <auto ...>
struct bar
{ };
int main ()
{
foo(bar<0, 1>{}); // compile both
foo(bar<0, 1L>{}); // only clang++ compile; error from g++
}
Live demo
clang++ (8.0.0, by example) compile and link without problem where g++ (9.2.0, by example) gives the following error compiling the second foo()
(but not the first) call
prog.cc: In function 'int main()':
prog.cc:16:20: error: no matching function for call to 'foo(bar<0, 1>)'
16 | foo(bar<0, 1L>{}); // only clang++ compile; error from g++
| ^
prog.cc:6:6: note: candidate: 'template<template<auto ...<anonymous> > class Cnt, class ... Types, Types ...Vals> void foo(Cnt<Vals ...>)'
6 | void foo (Cnt<Vals...>)
| ^~~
prog.cc:6:6: note: template argument deduction/substitution failed:
prog.cc:16:20: note: mismatched types 'int' and 'long int'
16 | foo(bar<0, 1L>{}); // only clang++ compile; error from g++
| ^
prog.cc:16:20: note: 'bar<0, 1>' is not derived from 'Cnt<Vals ...>'
If I understand correctly, g++ require that the Types...
of the Vals...
coincide where clang++ accept that the Vals...
are of different Types...
.
Who's right?
-- EDIT --
As pointed by Marek R (thanks) also MSVC (v19.22) fail to compile.
But, if I understand correctly, fail also compiling the first foo()
call with the following error
<source>(13): error C2672: 'foo': no matching overloaded function found
<source>(13): error C2893: Failed to specialize function template 'void foo(Cnt<Vals...>)'
<source>(13): note: With the following template arguments:
<source>(13): note: 'Cnt=bar'
<source>(13): note: 'Types={}'
<source>(13): note: 'Vals={0, 1}'
-- EDIT 2 --
camp0 observes (thanks) that g++ compile this code until version 7.4.
A bug introduced from 8.1 or is bugged my code and g++ has corrected his code from 8.1?
Variadic function templates in C++. Variadic templates are template that take a variable number of arguments. Variadic function templates are functions which can take multiple number of arguments.
Douglas Gregor and Jaakko Järvi came up with this feature for C++. Variadic arguments are very similar to arrays in C++. We can easily iterate through the arguments, find the size (length) of the template, can access the values by an index, and can slice the templates too.
Using variadic functions does indeed require a bit of a change in mindset, and is somewhat more verbose (given the amount of code required to write the base and recursive cases). However, these are the main tools you need for performing computation with variadics: unpack and reduce.
None of the three compilers is correct.
From [temp.param]/17:
If a template-parameter is a type-parameter with an ellipsis prior to its optional identifier or is a parameter-declaration that declares a pack ([dcl.fct]), then the template-parameter is a template parameter pack. A template parameter pack that is a parameter-declaration whose type contains one or more unexpanded packs is a pack expansion. ... A template parameter pack that is a pack expansion shall not expand a template parameter pack declared in the same template-parameter-list. [ Example:
...
template <class... T, T... Values> // error: Values expands template type parameter struct static_array; // pack T within the same template parameter list
— end example ]
So the code is ill-formed, even without the line foo(bar<0, 1L>{});
.
There is already a Clang bug report and a GCC bug report.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With