Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

g++ and clang++ different behaviour deducing variadic template `auto` values

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?

like image 349
max66 Avatar asked Aug 28 '19 09:08

max66


People also ask

What are variadic function templates in C++?

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.

What are variadic arguments in C++?

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.

What tools do you need to use variadic functions?

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.


1 Answers

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.

like image 57
xskxzr Avatar answered Oct 04 '22 15:10

xskxzr