Ambiguous Function Call?

My understanding for function call sequence is: exact matching function > template function.

However, below code yields "error: reference to ‘negate’ is ambiguous". Why is that?

1
2
3
4
5
6
7
8
9
int negate(int i) { return -i; }

template <class F>
auto negate(F f) { return -f(); }

int main()
{
    negate(1);
}
Last edited on
Why do you define "negate()" as auto right after the template? Also, why are you returning "-f()" with a function specifier? You don't declare it as a function anywhere in the program. You are correct as to which function has priority (see code below).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>

int negate (int i)
{
	return -i;
}

template <class F>
// Defined return type as F because that is the generic type
// defined by the template
F negate (F num)
{
	// This subtracts one to test which function takes priority
	return -num - 1;
}

int main()
{
	int num = 2;
	
	int num2 = negate (num); // call to int function
	int num3 = negate<int> (num);  // call to template function
	
	std::cout << num2 << std::endl;  // outputs -2
	std::cout << num3 << std::endl;  // outputs -3
	
	return 0;
}


The int function took priority when the call was ambiguous. Was this what you were trying to do?
Consider a C++20/2a version:
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

auto negate(auto f)
{
   return -f;
}

int main()
{
   std::cout << negate(1.1) << '\n';

   std::cout << negate(-2) << '\n';
}

-1.1
2
RicoJ, what compiler/version are you using? Compiles for me. Maybe explicitly pick C++14 or beyond as the language standard.
When I compile with just C++11, I get
4:16: note: deduced return type only available with -std=c++1y or -std=gnu++1y
Last edited on
error: reference to ‘negate’ is ambiguous

Do you use using namespace std somewhere in your code ?

There is a function object for performing negation in the STL that might cause the ambiguity
https://en.cppreference.com/w/cpp/utility/functional/negate
Hmm. When I used namespace std in Furry Guy's code, I got these errors:
test1.cc:5:13: error: 'auto' not allowed in function prototype
auto negate(auto f)
            ^~~~
test1.cc:12:12: error: no viable constructor or deduction guide for deduction of
      template arguments of 'negate'
   cout << negate(1.1) << '\n';
           ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/functional:639:29: note: 
      candidate template ignored: could not match 'negate<_Tp>' against 'double'
struct _LIBCPP_TEMPLATE_VIS negate : unary_function<_Tp, _Tp>
                            ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/functional:639:29: note: 
      candidate function template not viable: requires 0 arguments, but 1 was
      provided
test1.cc:14:12: error: no viable constructor or deduction guide for deduction of
      template arguments of 'negate'
   cout << negate(-2) << '\n';
           ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/functional:639:29: note: 
      candidate template ignored: could not match 'negate<_Tp>' against 'int'
struct _LIBCPP_TEMPLATE_VIS negate : unary_function<_Tp, _Tp>
                            ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/functional:639:29: note: 
      candidate function template not viable: requires 0 arguments, but 1 was
      provided
3 errors generated.

The first one is because my compiler doesn't support that particular C++20 functionality, but I'm not sure about the others.

Yeah, when I removed namespace std, it got rid of those last two errors. I think its a namespace std issue.
This compiles OK as C++17/20 with VS2019:

1
2
3
4
5
6
7
8
9
int negate(int i) { return -i; }

template <class F>
auto negate(F f) { return -f(); }

int main()
{
	negate(1);
}


So does this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
using namespace std;

int negate(int i)
{
	return -i;
}

template <class F>
F negate(F num)
{
	return -num - 1;
}

int main()
{
	int num = 2;
	int num2 = negate(num); // call to int function
	int num3 = negate<int>(num);  // call to template function

	cout << num2 << std::endl;  // outputs -2
	cout << num3 << std::endl;  // outputs -3
}


and so does this as C++20:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

auto negate(auto f)
{
	return -f;
}

int main()
{
	std::cout << negate(1.1) << '\n';

	std::cout << negate(-2) << '\n';
}




Last edited on
There is an unconstrained class template std::negate
https://en.cppreference.com/w/cpp/utility/functional/negate
This is why you don't say using namespace std, especially if you expect your code to compile on someone else's computer.
Last edited on
Yup! What you can do instead:
1
2
3
4
5
6
7
using std::cout;
using std::endl;
using std::cin;
using std::string;
using std::vector;
using std::getline;
// etc etc etc 


Takes up a little more space than "using namespace std" (and TBH I'd just use std:: if my program had fewer than about 10 cout objects), but it won't cause you any errors!
Using VS2019, this compiles:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <functional>
//using namespace std;

int negate(int i)
{
	return -i;
}

template <class F>
F negate(F num)
{
	return -num - 1;
}

int main()
{
	int num = 2;
	int num2 = negate(num); // call to int function
	int num3 = negate<int>(num);  // call to template function

	std::cout << num2 << std::endl;  // outputs -2
	std::cout << num3 << std::endl;  // outputs -3
}


whereas this doesn't with the using:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <functional>
using namespace std;

int negate(int i)
{
	return -i;
}

template <class F>
F negate(F num)
{
	return -num - 1;
}

int main()
{
	int num = 2;
	int num2 = negate(num); // call to int function
	int num3 = negate<int>(num);  // call to template function

	std::cout << num2 << std::endl;  // outputs -2
	std::cout << num3 << std::endl;  // outputs -3
}


This seems to be compiler dependent as to what other includes are also included with iostream etc.
Hi guys, Y'all have raised some very nice points! Yes, I did have
1
2
#include <functional>
using namespace std; 

Now I know the existence of std::negate. Thanks for bringing this up!
Last edited on
Topic archived. No new replies allowed.