Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ambiguity error in C++17 (template template parameters and default arguments issue)

Tags:

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.

like image 223
Yuri Dolotkazin Avatar asked Aug 17 '18 10:08

Yuri Dolotkazin


People also ask

Can template have default parameters?

You cannot give default arguments to the same template parameters in different declarations in the same scope. The compiler will not allow the following example: template<class T = char> class X; template<class T = char> class X { };

Can default argument be used with the template class?

Can default arguments be used with the template class? Explanation: The template class can use default arguments.

Can we pass Nontype parameters to templates?

Template non-type arguments in C++It is also possible to use non-type arguments (basic/derived data types) i.e., in addition to the type argument T, it can also use other arguments such as strings, function names, constant expressions, and built-in data types.

What is template argument deduction in C++?

Class Template Argument Deduction (CTAD) is a C++17 Core Language feature that reduces code verbosity. C++17's Standard Library also supports CTAD, so after upgrading your toolset, you can take advantage of this new feature when using STL types like std::pair and std::vector.


1 Answers

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 
like image 152
songyuanyao Avatar answered Sep 27 '22 02:09

songyuanyao