when using templates C++ "const" mystery overloaded function call - c++

I have a question with the code below. When I compile it it complains with this error below. Now my question is if I remove the "const" in the declaration and change it to only :
template<class T> T max( T& left, T& right);
it becomes okay and the compiles/executes correctly. How come the compiler thinks that the call is ambiguous? Shouldn't the forward declaration follow the implementation?
==== start of error message====
max.cpp:10:34: error: call of overloaded ‘max(int, int)’ is ambiguous
max.cpp:10:34: note: candidates are:
max.cpp:5:21: note: T max(const T&, const T&) [with T = int]
/usr/include/c++/4.6/bits/stl_algobase.h:210:5: note: const _Tp& std::max(const _Tp&, const _Tp&) [with _Tp = int]
max.cpp:11:44: error: call of overloaded ‘max(double, double)’ is ambiguous
max.cpp:11:44: note: candidates are:
max.cpp:5:21: note: T max(const T&, const T&) [with T = double]
=======end of error message===
=============code starts here======
#include<iostream>
using namespace std;
template<class T> T max(const T& left, const T& right);
int main(void)
{
cout<<"max int:"<< max(1,4)<<endl;
cout<<"max double:"<< max(5.02,1.002)<<endl;
}
template<class T>
T max(const T& left, const T& right)
{
return left > right? left:right;
}

You have to do:
cout<<"max int:"<< ::max(1,4)<<endl;
cout<<"max double:"<< ::max(5.02,1.002)<<endl;
Since there is another max defined in std namespace. You have to inform the compiler to use the max defined in global namespace, which is the one you defined. See a live example here: Function template Demo
If you look at the std::max defined in std namespace:
template <class T> const T& max (const T& a, const T& b);
which returns const reference and takes const reference to parameters, that's why when you remove const, it will compile. Hope that this helps.

The std namespace has a max already built in, so you can either not have the line using namespace std; or put the max function in your own namespace.
namespace myNamespace {
//your max function
}

We have few functions already defined in std namespace like max(), swap() qsort(). So when you define your own function
max(const T& left,const T& right)
it is same as one in std namespace hence the error. So you can do following to make it work
call your function using scope resolution operator ::max(x,y)
remove const qualifier from your function

As others have written the compiler has found a max function additionally in namespace std. Now it tries to get the best version for you via function overloading. As both signatures are eaqual it can not choose a best version and complains. Now if you remove const the compiler can not bind a integer (or double) literal to a non const refference. Now it has only one choice and takes std::max functionality. You can see it with the following example:
#include <iostream>
namespace ns1 {
template<class T>
void doit(T const&) {
std::cout << "ns1::doit" << std::endl;
}
}
template<class T>
void doit(T&) {
std::cout << "::doit" << std::endl;
}
int main() {
using namespace ns1;
int i=1;
int const j=1;
doit(1);
doit(i);
doit(i+1-1);
doit(j);
return 0;
}
As everithing is an int the compiler has to choose a non const reference only if it has a non const variable (i). In other cases it choose the cont reference version from namespace ns1. It could even bind temporaries to const references (i+1-1).The same happens with your max and std::max.
Edit:
I forgott to say if you remove the const in your declaration the compiler choose std::max which is of course correct but not yours.

Related

operator== does not compile if I include <iostream>

The following code compiles perfectly if:
I don't include <iostream> or
I name operator== as alp::operator==.
I suppose there is a problem with <iostream> and operator==, but I don't know what.
I compile the code with gcc 7.3.0, clang++-6.0 and goldbolt. Always the same error.
The problem is that the compiler is trying to cast the parameters of operator== to const_iterator, but why? (I suppose the compiler doesn't see my version of operator==, and looks for other versions).
#include <vector>
#include <iostream> // comment and compile
namespace alp{
template <typename It_base>
struct Iterator {
using const_iterator = Iterator<typename It_base::const_iterator>;
operator const_iterator() { return const_iterator{}; }
};
template <typename It_base>
bool operator==(const Iterator<It_base>& x, const Iterator<It_base>& y)
{ return true;}
}// namespace
struct Func{
int& operator()(int& p) const {return p;}
};
template <typename It, typename View>
struct View_iterator_base{
using return_type = decltype(View{}(*It{}));
using const_iterator =
View_iterator_base<std::vector<int>::const_iterator, Func>;
};
using view_it =
alp::Iterator<View_iterator_base<std::vector<int>::iterator, Func>>;
int main()
{
view_it p{};
view_it z{};
bool x = operator==(z, p); // only compiles if you remove <iostream>
bool y = alp::operator==(z,p); // always compile
}
Error message:
yy.cpp: In instantiation of ‘struct View_iterator_base<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func>’:
yy.cpp:9:73: required from ‘struct alp::Iterator<View_iterator_base<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func> >’
yy.cpp:44:29: required from here
yy.cpp:28:42: error: no match for call to ‘(Func) (const int&)’
using return_type = decltype(View{}(*It{}));
~~~~~~^~~~~~~
yy.cpp:22:10: note: candidate: int& Func::operator()(int&) const <near match>
int& operator()(int& p) const {return p;}
^~~~~~~~
yy.cpp:22:10: note: conversion of argument 1 would be ill-formed:
yy.cpp:28:42: error: binding reference of type ‘int&’ to ‘const int’ discards qualifiers
using return_type = decltype(View{}(*It{}));
~~~~~~^~~~~~~
I've made a more minimal test case here: https://godbolt.org/z/QQonMG .
The relevant details are:
A using type alias does not instantiate a template. So for example:
template<bool b>
struct fail_if_true {
static_assert(!b, "template parameter must be false");
};
using fail_if_used = fail_if_true<true>;
will not cause a compile time error (if fail_if_used isn't used)
ADL also inspects template parameter classes. In this case, std::vector<int>::iterator is __gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func>, which has a std::vector<int> in it's template. So, operator== will check in the global namespace (always), alp (As alp::Iterator is in alp), __gnu_cxx and std.
Your View_iterator_base::const_iterator is invalid. View_iterator_base::const_interator::result_type is defined as decltype(Func{}(*std::vector<int>::const_iterator{})). std::vector<int>::const_iterator{} will be a vectors const iterator, so *std::vector<int>::const_iterator{} is a const int&. Func::operator() takes an int&, so this means that the expression is invalid. But it won't cause a compile time error if not used, for the reasons stated above. This means that your conversion operator is to an invalid type.
Since you don't define it as explicit, the conversion operator (To an invalid type) will be used to try and match it to the function parameters if they don't already match. Obviously this will finally instantiate the invalid type, so it will throw a compile time error.
My guess is that iostream includes string, which defines std::operator== for strings.
Here's an example without the std namespace: https://godbolt.org/z/-wlAmv
// Avoid including headers for testing without std::
template<class T> struct is_const { static constexpr const bool value = false; } template<class T> struct is_const<const T> { static constexpr const bool value = true; }
namespace with_another_equals {
struct T {};
bool operator==(const T&, const T&) {
return true;
}
}
namespace ns {
template<class T>
struct wrapper {
using invalid_wrapper = wrapper<typename T::invalid>;
operator invalid_wrapper() {}
};
template<class T>
bool operator==(const wrapper<T>&, const wrapper<T>&) {
return true;
}
}
template<class T>
struct with_invalid {
static_assert(!is_const<T>::value, "Invalid if const");
using invalid = with_invalid<const T>;
};
template<class T>
void test() {
using wrapped = ns::wrapper<with_invalid<T>>;
wrapped a;
wrapped b;
bool x = operator==(a, b);
bool y = ns::operator==(a, b);
}
template void test<int*>();
// Will compile if this line is commented out
template void test<with_another_equals::T>();
Note that just declaring operator const_iterator() should instantiate the type. But it doesn't because it is within templates. My guess is that it is optimised out (where it does compile because it's unused) before it can be checked to show that it can't compile (It doesn't even warn with -Wall -pedantic that it doesn't have a return statement in my example).

Why does this C++ generic function work by reference but doesn't work by value? [duplicate]

#include <iostream>
using namespace std;
template<typename T>
T max(T lhs, T rhs)
{
return lhs < rhs ? rhs : lhs;
}
template<>
int max<int>(int lhs, int rhs)
{
return lhs < rhs ? rhs : lhs;
}
int main()
{
cout << max<int>(4, 5) << endl;
}
~/Documents/C++/boost $ g++ -o testSTL testSTL.cpp -Wall
testSTL.cpp: In function ‘int main()’:
testSTL.cpp:18:24: error: call of overloaded ‘max(int, int)’ is ambiguous
testSTL.cpp:11:5: note: candidates are: T max(T, T) [with T = int]
/usr/include/c++/4.5/bits/stl_algobase.h:209:5: note: const _Tp& std::max(const _Tp&, const _Tp&) [with _Tp = int]
How do I correct this error?
It's all because of your using namespace std;. Remove that line.
By that using-directive, you bring std::max (which must be somehow included via iostream) into the global scope. Therefore the compiler doesn't know which max to call - ::max or std::max.
I hope this example will be a good scarecrow for those who think that using directives come at no cost. Weird errors are one side effect.
I guess the compiler can't work out whether to use std::max or your max, because you've got a using namespace std; and both your max and the std::max fit the bill
You're colliding with std::max(). Rename it to something else like mymax and it will work.
You have both your max and std::max. The compiler doesn't know which one you intended to call.
You can tell it by calling ::max(4,5) or std::max(4,5), or - even better - not have using namespace std in the file.
That's because there's already std::max template function defined.
Remove the 'using namespace std' and add 'std::' where needed., or use '::max'.
The problem is that there is already a function named 'max' defined by std. To fix this, rename your function to something else, like this:
#include <iostream>
using namespace std;
template<typename T>
T mymax(T lhs, T rhs)
{
return lhs < rhs ? rhs : lhs;
}
template<>
int mymax<int>(int lhs, int rhs)
{
return lhs < rhs ? rhs : lhs;
}
int main()
{
cout << mymax<int>(4, 5) << endl;
return 0;
}

error: call of overloaded ‘max(int, int)’ is ambiguous

#include <iostream>
using namespace std;
template<typename T>
T max(T lhs, T rhs)
{
return lhs < rhs ? rhs : lhs;
}
template<>
int max<int>(int lhs, int rhs)
{
return lhs < rhs ? rhs : lhs;
}
int main()
{
cout << max<int>(4, 5) << endl;
}
~/Documents/C++/boost $ g++ -o testSTL testSTL.cpp -Wall
testSTL.cpp: In function ‘int main()’:
testSTL.cpp:18:24: error: call of overloaded ‘max(int, int)’ is ambiguous
testSTL.cpp:11:5: note: candidates are: T max(T, T) [with T = int]
/usr/include/c++/4.5/bits/stl_algobase.h:209:5: note: const _Tp& std::max(const _Tp&, const _Tp&) [with _Tp = int]
How do I correct this error?
It's all because of your using namespace std;. Remove that line.
By that using-directive, you bring std::max (which must be somehow included via iostream) into the global scope. Therefore the compiler doesn't know which max to call - ::max or std::max.
I hope this example will be a good scarecrow for those who think that using directives come at no cost. Weird errors are one side effect.
I guess the compiler can't work out whether to use std::max or your max, because you've got a using namespace std; and both your max and the std::max fit the bill
You're colliding with std::max(). Rename it to something else like mymax and it will work.
You have both your max and std::max. The compiler doesn't know which one you intended to call.
You can tell it by calling ::max(4,5) or std::max(4,5), or - even better - not have using namespace std in the file.
That's because there's already std::max template function defined.
Remove the 'using namespace std' and add 'std::' where needed., or use '::max'.
The problem is that there is already a function named 'max' defined by std. To fix this, rename your function to something else, like this:
#include <iostream>
using namespace std;
template<typename T>
T mymax(T lhs, T rhs)
{
return lhs < rhs ? rhs : lhs;
}
template<>
int mymax<int>(int lhs, int rhs)
{
return lhs < rhs ? rhs : lhs;
}
int main()
{
cout << mymax<int>(4, 5) << endl;
return 0;
}

Unnamed namespace and iostream result in "!= being illegal operation"

#include <functional>
#include <iostream>
struct A {
friend bool operator==( const A & a, const A & b ){
return true;
}
};
namespace {
bool operator!=( const A &a, const A & b){
return !(a==b);
}
}
int main(int argc, char **argv) {
std::not_equal_to<A> neq;
A a;
bool test = neq(a, a);
return test ? 0 : 1;
}
This fails on CC (SunOs Compiler) with:
Error: The operation "const A != const A" is illegal.
"tempcc.cpp", line 16: Where: While instantiating "std::not_equal_to<A>::operator()(const A&, const A&) const".
"tempcc.cpp", line 16: Where: Instantiated from non-template code.
And on g++ with:
/usr/local/include/c++/3.3.2/bits/stl_function.h: In member function `bool std::not_equal_to<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = A]':
tempcc.cpp:16: instantiated from here
/usr/local/include/c++/3.3.2/bits/stl_function.h:183: error: no match for 'operator!=' in '__x != __y'
However if I remove the line #include <iostream> it compiles and runs just fine. Anyone dare to explain this?
According to Comeau, this isn't legal either way - the fact that the compiler builds it when you don't #include <iostream> may be the actual bug, not the other way around (or at least a disagreement in interpretation):
"stl_function.h", line 99: error: no operator "!=" matches these operands
operand types are: const A != const A
bool operator()(const _Tp& __x, const _Tp& __y) const { return __x != __y; }
^
detected during instantiation of "bool
std::not_equal_to<_Tp>::operator()(const _Tp &, const _Tp
&) const [with _Tp=A]" at line 19 of "ComeauTest.c"
"ComeauTest.c", line 10: warning: function "<unnamed>::operator!=" was declared but
never referenced
bool operator!=( const A &a, const A & b){
^
It makes sense that this doesn't build - placing operator!= in an unnamed namespace still puts it in a different namespace than ::, and I'm not entirely sure why g++ builds it without the iostream include - if you look at the preprocessor output from g++ it hasn't done anything hinky to reorder code or any such nonsense, and of course iostream doesn't define operator!= for A.
I do not have my copy of the C++ standard handy, but this link from IBM at least validates the claim that unnamed namespaces don't mix that well with the global one, explaining why you can't find the operator!= you've defined.
You also might find some helpful information in Anonymous Namespace Ambiguity.
The problem is that <functional> also pulls in several templates from from tuple and utility that interfere with the lookup.
If you were to remove this, e.g. by only including <bits/stl_function.h> in GCC, then there is no problem, although is is of course not a real solution. I suppose you cannot get around either implementing your own operator!=() or adding an explicit specialization for std::not_equal_to if you require the predicate.
However, if you don't need to use the not_equal_to predicate, you can circumvent the problem entirely by removing all your custom code and adding the following:
#include <utility>
using namespace std::rel_ops;
bool test = a != a;

C++ boost function overloaded template

I cannot figure out why this segment gives unresolved overloaded function error (gcc version 4.3.4 (Debian 4.3.4-6)):
#include <algorithm>
#include <boost/function.hpp>
// this does not work
int main1()
{
typedef boost::function<const int&(const int&, const int&)> max;
max m(&std::max<int>);
}
// this does not work
int main2() {
typedef boost::function2<const int&, const int&, const int&> max;
max m(static_cast<max>(&std::max<int>));
}
can you help me, thanks
test.cpp: In function âint main()â:
test.cpp:7: error: no matching function for call to âboost::function2<const int&, const int&, const int&>::function2(<unresolved overloaded function type>)â
/usr/include/boost/function/function_template.hpp:747: note: candidates are: boost::function2<R, T1, T2>::function2(const boost::function2<R, T1, T2>&) [with R = const int&, T0 = const int&\
, T1 = const int&]
/usr/include/boost/function/function_template.hpp:739: note: boost::function2<R, T1, T2>::function2(boost::function2<R, T1, T2>::clear_type*) [with R = const int&, T0 = cons\
t int&, T1 = const int&]
/usr/include/boost/function/function_template.hpp:707: note: boost::function2<R, T1, T2>::function2() [with R = const int&, T0 = const int&, T1 = const int&]
max/min is defined as
template<typename _Tp>
inline const _Tp&
max(const _Tp& __a, const _Tp& __b)
{
// concept requirements
__glibcxx_function_requires(_LessThanComparableConcept<_Tp>)
//return __a < __b ? __b : __a;
if (__a < __b)
return __b;
return __a;
}
I have tried all sorts of template explicit instantiation but nothing seems to work. Same problem appears with g++ 4.1 but not with ICC
this works
#include <algorithm>
#include <boost/function.hpp>
namespace std_ {
template<typename _Tp>
inline const _Tp&
max(const _Tp& __a, const _Tp& __b)
{
// concept requirements
//return __a < __b ? __b : __a;
if (__a < __b)
return __b;
return __a;
}
}
int main()
{
typedef const int &T;
typedef boost::function<T(T,T)> min_;
//typedef const int&(*min_)(const int&, const int&);
min_ m(::std_::max<int>);
}
and this
#include <algorithm>
#include <boost/function.hpp>
int main()
{
//typedef const int &T;
//typedef boost::function<T(T,T)> min_;
typedef const int&(*min_)(const int&, const int&);
min_ m(::std::max<int>);
}
Update: this is a gcc bug that has been fixed in gcc >=4.4. bugzilla. Also, revised my answer with a reduced test case.
There are two components to this problem: the way boost::function adopts a function pointer and the gcc bug.
boost::function - There is something strange about the error message you listed in the question; there is no candidate constructor that accepts anything like a function address. Digging into the boost::function src, the relevant constructor is (leaving out the enable_if argument):
template<typename Functor>
function(Functor f) : base_type(f) {}
So boost::function doesn't help you out at all in specifying the type of a function pointer; if the function is overloaded the address must be cast to specify its type. If an overloaded function address is used, the above template can't be instantiated, and therefore the appropriate constructor doesn't show up in the error message.
gcc bug - If you look at the stl_algobase.h header again, you'll see there are two templates named max, a two param version and a one param version. This shouldn't be a problem with you code though, right? The term &max<int> should instantiate the single param version and take its address. However, that is not what happens. You can see the problem in the reduced (no header) test case:
template <class T>
const T& max(const T& x, const T& y){
return x > y ? x : y;
}
template <class T, class C>
const T& max(const T& x, const T& y, C comp){
return comp(x, y) ? y : x;
}
template <class R, class A0, class A1>
struct functor{
template <class F>
functor(F f) : f(f) {}
R (*f)(A0, A1);
};
int main(void){
functor<const int&, const int&, const int&> func(&max<int>);
return 0;
}
The above code results in a unresolved overloaded function type with gcc 4.3.4. The fix is either to remove the template <class T, class C> max(...){...} definition or add a static_cast<const int& (*)(const int&, const int&)>(...) around the function address. I'm guessing the problem has to do with incorrect application of partial explicit parameter specification, which is specified by the standard. It lets you leave out trailing template parameters to do things like specify a return value type and not the argument types. That is, the compiler instantiates both template when it should only instantiate the fully specified template. Its moot speculation though, since the bug has been fixed in gcc >= 4.4.
Since one shouldn't hack at stl_algobase.h ;) , the work around Vicente suggests is the correct one, namely cast the function pointer to the desired function pointer type const int& (*)(const int&, const int&). In your code, the cast doesn't work because, as GMan points out, you are casting to a boost::function<...>, which does nothing to resolve the function pointer ambiguity.
To critique the code, there's no reason to static_cast that. Consider all the cast is going to do is use the constructor of boost::function2 to make a new boost::function2, then it will be copy-constructed into m. Just construct directly into m:
#include <algorithm>
#include <boost/function.hpp>
int main()
{
typedef boost::function2<const int&, const int&, const int&> max;
max m(&std::max<int>);
}
Lastly, the preferred syntax of boost::function is:
#include <algorithm>
#include <boost/function.hpp>
int main()
{
typedef boost::function<const int&(const int&, const int&)> max;
max m(&std::max<int>);
}
The n-ary specific classes are for older compiler support.
It seems to be a problem with the definition of the std::max template function with releases of gcc < 4.4
With gcc-4.4.0 and msvc Express9 it works.
The following works also for gcc-3.4 and gcc-4.3
int main1()
{
int res = std::max(1,2);
typedef boost::function<const int&(const int&, const int&)> max;
max m(static_cast<const int&(*)(const int&, const int&)>(std::max<int>));
return 0
}