https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114695
Bug ID: 114695 Summary: Template argument deduction and defaulted template template parameters Product: gcc Version: 13.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: vin.piquet at gmail dot com Target Milestone: --- ==== test.cpp ==== template <int Y, typename X> struct Bar { void accept(X value) { } }; template <typename...> struct Foo; template <int... Is, typename... Ts> struct Foo<Bar<Is, Ts>...> : Bar<Is, Ts>... { template <typename T, int I, template <int, typename> typename B = Bar> constexpr static B<I, T>* slice_by_type(B<I, T>* self) { return self; } template <typename... Us> void accept(Us... values) { (slice_by_type<Us>(this)->accept(values), ...); } }; int main() { Foo<Bar<0, float>, Bar<1, int>> foo; foo.accept(3.14f, 10); } ==== test.cpp ==== GCC rejects this code with the following error ==== console output for GCC 13.2 ==== test.cpp: In instantiation of 'void Foo<Bar<Is, Ts>...>::accept(Us ...) [with Us = {float, int}; int ...Is = {0, 1}; Ts = {float, int}]': test.cpp:22:15: required from here test.cpp:16:27: error: no matching function for call to 'Foo<Bar<0, float>, Bar<1, int> >::slice_by_type<float>(Foo<Bar<0, float>, Bar<1, int> >*)' 16 | (slice_by_type<Us>(this)->accept(values), ...); | ~~~~~~~~~~~~~~~~~^~~~~~ test.cpp:10:31: note: candidate: 'template<class T, int I, template<int <anonymous>, class> class B> static constexpr B<I, T>* Foo<Bar<Is, Ts>...>::slice_by_type(B<I, T>*) [with int I = T; B = I; int ...Is = {0, 1}; Ts = {float, int}]' 10 | constexpr static B<I, T>* slice_by_type(B<I, T>* self) { | ^~~~~~~~~~~~~ test.cpp:10:31: note: template argument deduction/substitution failed: test.cpp:16:27: note: 'B<I, T>' is an ambiguous base class of 'Foo<Bar<0, float>, Bar<1, int> >' 16 | (slice_by_type<Us>(this)->accept(values), ...); | ~~~~~~~~~~~~~~~~~^~~~~~ This appears to be a consequence of GCC matching T to I somehow and getting confused. I can't really tell what's going on here, except that the fact GCC seems to not deduce I = 0 supposedly because B<I, T> is not deduced to Bar<0, float>. Interestingly, GCC 6.3 also rejects this code, with a somewhat more clear error: ==== Console output for GCC 6.3 ==== test.cpp: In instantiation of 'void Foo<Bar<Is, Ts>...>::accept(Us ...) [with Us = {float, int}; int ...Is = {0, 1}; Ts = {float, int}]': <source>:22:25: required from here <source>:16:27: error: no matching function for call to 'Foo<Bar<0, float>, Bar<1, int> >::slice_by_type(Foo<Bar<0, float>, Bar<1, int> >*)' (slice_by_type<Us>(this)->accept(values), ...); ~~~~~~~~~~~~~~~~~^~~~~~ test.cpp:10:31: note: candidate: template<class T, int I, template<int <anonymous>, class> class B> static constexpr B<I, T>* Foo<Bar<Is, Ts>...>::slice_by_type(B<I, T>*) [with T = T; int I = I; B = B; int ...Is = {0, 1}; Ts = {float, int}] constexpr static B<I, T>* slice_by_type(B<I, T>* self) { ^~~~~~~~~~~~~ test.cpp:10:31: note: template argument deduction/substitution failed: test.cpp:16:27: error: type/value mismatch at argument 1 in template parameter list for 'template<int <anonymous>, class> class B' (slice_by_type<Us>(this)->accept(values), ...); ~~~~~~~~~~~~~~~~~^~~~~~ test.cpp:16:27: note: expected a constant of type 'int', got 'Bar<0, float>' ==== Console output for GCC 6.3 ==== MSVC accepts this code in C++20 but rejects it in C++17 with a similar error; Clang accepts this code on both versions since Clang 5.0.0 Relevant godbolt link: https:~~godbolt.org~z~48zs7KnTo (replace tildes) ==== Compiler version ==== Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/libexec/gcc/aarch64-linux-gnu/13/lto-wrapper Target: aarch64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 13.2.0-4ubuntu3' --with-bugurl=file:///usr/share/doc/gcc-13/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-13 --program-prefix=aarch64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libquadmath --disable-libquadmath-support --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --enable-fix-cortex-a53-843419 --disable-werror --enable-checking=release --build=aarch64-linux-gnu --host=aarch64-linux-gnu --target=aarch64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2 Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 13.2.0 (Ubuntu 13.2.0-4ubuntu3) ==== Compiler version === Thank you :)