g++ 8.1 template deduction ambiguity with std flag equal to 'c++17'

  • A+

I have code which is differently interpreted by g++ with the c++14 and c++17 standard flags:

#include <iostream> #include <vector>  template<class T, class A> void func(const std::vector<T, A>&v) {     std::cout << 1 << std::endl; }  template<typename T, template <typename>class Vector> void func(const Vector<T>&v) {     std::cout << 2 << std::endl; }  void f() {     std::vector<int> v;     func(v); }  int main() {     f();     return 0; } 

When I'm trying compile this code with command

g++ -std=c++14 -Wall -pedantic main.cpp

everything works just fine.

But when I'm trying to compile this code with command

g++ -std=c++17 -Wall -pedantic main.cpp

I get this error:

main.cpp: In function 'void f()': main.cpp:19:11: error: call of overloaded 'func(std::vector<int>&)' is ambiguous      func(v);            ^ main.cpp:5:6: note: candidate: 'void func(const std::vector<_Tp, _Alloc>&) [with T = int; A = std::allocator<int>]'  void func(const std::vector<T, A>&v)       ^~~~ main.cpp:11:6: note: candidate: 'void func(const Vector<T>&) [with T = int; Vector = std::vector]'  void func(const Vector<T>&v) 

I can't figure out what is wrong with this code from the C++17 standard's point of view.


The behavior changed since C++17.

Before C++17, the code works because std::vector has two template parameters (the 2nd one has the default argument std::allocator<T>), while the template template parameter Vector is declared to have only one, they don't match then the 2nd func won't be considered.

Since C++17 (CWG 150), the default template arguments are allowed for a template template argument to match a template template parameter with fewer template parameters. That means both func become valid candidates and then leads to ambiguity.

template<class T> class A { /* ... */ }; template<class T, class U = T> class B { /* ... */ };  template<template<class> class P> class X { /* ... */ };  X<A> xa; // OK X<B> xb; // OK in C++17 after CWG 150          // Error earlier: not an exact match 


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: