Why does a global merge() function conflict with std::merge()? - c++

Consider the following code:
#include <vector>
#include <algorithm>
template <typename Input1, typename Input2, typename Output>
void merge(Input1 begin1, Input1 end1, Input2 begin2, Input2 end2, Output out)
{
}
int main()
{
std::vector<int> a = {1, 2};
int b[] = {3, 4};
int c[4];
merge(a.begin(), a.end(), b, b + 2, c);
}
Compiling yields:
$ clang++ -std=c++11 -stdlib=libc++ merge.cpp
merge.cpp:15:5: error: call to 'merge' is ambiguous
merge(a.begin(), a.end(), b, b + 2, c);
^~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/algorithm:4056:1: note:
candidate function [with _InputIterator1 = std::__1::__wrap_iter<int *>,
_InputIterator2 = int *, _OutputIterator = int *]
merge(_InputIterator1 __first1, _InputIterator1 __last1,
^
merge.cpp:5:6: note: candidate function [with Input1 = std::__1::__wrap_iter<int
*>, Input2 = int *, Output = int *]
void merge(Input1 begin1, Input1 end1, Input2 begin2, Input2 end2, Output out)
^
1 error generated.
Compiler version:
$ clang++ --version
Apple LLVM version 5.0 (clang-500.2.78) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.0.0
Thread model: posix
Why is the call to merge ambiguous? It's not sure if I meant ::merge() or std::merge(), though clearly(?) it should be ::merge() since I'm not specifying any using directives. My merge function is in the global namespace, which I thought wouldn't conflict with anything in the std namespace (since that's the main point of namespaces, right?). If I change a to be an int array like the others, it compiles without any ambiguity. Also, adding the colons and calling ::merge() works fine.
So my question is this: Is this a bug in Clang, or do I have a misunderstanding of namespaces? Why does my call to merge() result in ambiguity when the two functions aren't in the same namespace and I haven't made std::merge() visible with any using directives?

The problem is that std::vector<T>::iterator may be a class type (in your case, it is a class type): during overload resolution the compiler finds all visible declarations of a function. To this end, it goes looking in namespaces possibly associated with its arguments (this is called argument dependent look-up). The type std::vector<T>::iterator is defined in namespace std (or a namespace nested within) and, thus, function from namespace std are considered for overload resolutions. Since std::merge() and your merge() both match equally well, there is an ambiguity.
The easiest way to avoid the problem is to use a different name for the function template. Hiding the associated namespace is possible but not easy: associated namespaces are taken from the location where a class or a class template is defined as well as from its base classes and template arguments. Thus, creating a wrapper template for any iterator type wouldn't be sufficient as it still associates the original namespace with the types. You may try to make your function template a better match but given that it is meant to be as generic as the standard algorithm, this isn't quite viable, either.

It's due to argument dependent look-up (http://en.cppreference.com/w/cpp/language/adl) of an iterator from the std namespace.
you could write ::merge to get your function only, but I'd rather just use a different name.

Related

template operator visibility, gcc vs clang

I have this code, relying on a fold expression calling a very generic comparison operator:
#include <type_traits>
#include <vector>
#include <list>
template <typename Iter_a, typename Iter_b>
auto operator<(Iter_a, Iter_b) {
// original code makes more sense, I assure you
if constexpr ( std::is_same_v<Iter_a, Iter_b> ) {
return Iter_a();
}
else return Iter_b();
}
template <typename... Iterators>
using weakest_iterator = std::decay_t<decltype( (Iterators() < ...) )>;
int main() {
using lit = std::list<int>::iterator;
using vit = std::vector<int>::iterator;
using wi = weakest_iterator<lit, vit, float*>;
}
I have two problems with this code:
The first is that g++ compiles it and clang++ (-std=gnu++2a) refuses to do so:
prog.cc:14:64: error: call to function 'operator<' that is neither visible in the template definition nor found by argument-dependent lookup
using weakest_iterator = std::decay_t<decltype( (Iterators() < ...) )>;
^
prog.cc:19:16: note: in instantiation of template type alias 'weakest_iterator' requested here
using wi = weakest_iterator<lit, vit, float*>;
^
prog.cc:6:6: note: 'operator<' should be declared prior to the call site
auto operator<(Iter_a, Iter_b) {
Do you have any idea why? I find particularly troubling that clang requests a definition prior to the call site at line 19, that it finds by itself at line 6.
The second is that, if I modify it to invoke my meta-function with pointer template arguments (using wi = weakest_iterator<int*, float*, float*>;, I get another error message, this time only with g++ since clang refuses to compile, that I find difficult to really understand:
main.cpp: In substitution of 'template<class ... Iterators> using weakest_iterator = std::decay_t<decltype ((Iterators() < ...))> [with Iterators = {int*, float*, float*}]':
main.cpp:19:57: required from here
main.cpp:14:75: error: ISO C++ forbids comparison between pointer and integer [-fpermissive]
using weakest_iterator = std::decay_t<decltype( (Iterators() < ...) )>;
It seems that 1) the built-in overload of operator< is called (if there is anything such as this) over my ultra-generic one, and 2) that comparing an int* and a float* is considered the same as comparing a pointer and an integer.
Is it possible to make sure that my own implementation of operator< is chosen by the compiler?

Ambiguous Function Call when One Definition is in a Namespace

I have a simple program containing the following code:
namespace nam
{
struct S{};
void f(S *){}
}
void f(nam::S *){}
int main()
{
nam::f(nullptr);
nam::S s;
f(&s);
return 0;
}
I expect that this will compile fine because I am calling f the second time without specifying namespace nam. However, upon compiling the code, I get this error:
$ g++ main.cpp -std=c++11 -Wall -Wextra
main.cpp: In function ‘int main()’:
main.cpp:14:9: error: call of overloaded ‘f(nam::S*)’ is ambiguous
f(&s);
^
main.cpp:7:6: note: candidate: void f(nam::S*)
void f(nam::S *){}
^
main.cpp:4:10: note: candidate: void nam::f(nam::S*)
void f(S *){}
Compiler and version:
$ gcc --version
gcc (Debian 5.3.1-14) 5.3.1 20160409
After trying this with different compilers, similar errors are returned. This seems to be a defined part of C++. I can't find anywhere on the internet where it says that calling a function with a struct in namespace nam as a parameter effectively implies using namespace nam; and requires ::f to remove ambiguity. I have 2 questions about this:
Where is this defined in the C++ standard?
Is there a good reason for this behavior?
Personally I like to avoid using namespace x; and similar. I want the compiler to give me an error when I don't specify a namespace. This behavior stops the compiler from doing so, and this means my code is inconsistent in places, because I occasionally forget to specify the namespace when calling functions like f that are not declared globally anywhere.
Your implementation of f(nam::S*) is outside of the namespace of 'nam'
change:
void f(nam::S *){}
to:
void nam::f(nam::S *){}
(or just move the enclosing namespace bracket) and all should be fine.
if your call to f(&s) in the current namespace was intentional then you need to specify this by changing the function call to
::f(&s)
As was said in the comments, this is due to argument-dependent lookup. I guess now I'll have to figure out now if I want to always specify the namespace in my code where this would make it unnecessary, or never specify it.

Template function call ambiguity error

I am not familiar with templates. I've just started learning it. Why I am getting errors in following program?
#include <iostream>
#include <string>
using std::cout;
using std::string;
template<class C>
C min(C a,C b) {
return a<b?a:b;
}
int main()
{
string a="first string";
string b="second string";
cout<<"minimum string is: "<<min(a,b)<<'\n';
int c=3,d=5;
cout<<"minimum number is: "<<min(c,d)<<'\n';
double e{3.3},f{6.6};
cout<<"minimum number is: "<<min(e,f)<<'\n';
char g{'a'},h{'b'};
cout<<"minimum number is: "<<min(g,h)<<'\n';
return 0;
}
Errors:
13 [Error] call of overloaded 'min(std::string&, std::string&)' is ambiguous
6 [Note] C min(C, C) [with C = std::basic_string<char>]
Please help me.
There are a two things going on here.
Your first problem is that you only included part of the error message. Here is a link to the code being complied in gcc and clang, and one of the resulting error messages (in full):
main.cpp:13:34: error: call to 'min' is ambiguous
cout<<"minimum string is: "<<min(a,b)<<'\n';
^~~
/usr/include/c++/v1/algorithm:2579:1: note: candidate function [with _Tp = std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >]
min(const _Tp& __a, const _Tp& __b)
^
main.cpp:6:3: note: candidate function [with C = std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >]
C min(C a,C b) {
^
there are two candidates. One at main.cpp:6:3 (line 6, character 3) and one at algorithm:2579:1 (line 2579, character 1).
One of them you wrote, and one of them in #include <algorithm>.
One of your header files included <algorithm> without you asking for it. The standard headers are allowed to do this, as annoying as it is sometimes.
In <algorithm> there is a std::min function template. As std::string is an instance of a template class in namespace std, the function template std::min is found via a process called "argument dependent lookup" or "Koenig lookup". (function overload candidates are searched for locally, and also in the namespaces of the arguments to the function, and in the namespaces of the template arguments to the arguments to the function, and in the namespaces of the things pointed to by the arguments of the function, etc.)
Your local function min is also found, as it is in the same namespace as the body of main.
Both are equally good matches, and the compiler cannot decide which one you want to call. So it generates an error telling you this.
Both gcc and clang do error: then a sequence of note:s. Usually all of the note:s after an error are important to understanding the error.
To fix this, try calling ::min (fully qualifying the call), or renaming the function to something else, or make your version a better match than std::min (tricky, but doable in some cases), or calling (min)(a,b). The last blocks ADL/Koenig lookup, and also blocks macro expansion (for example, if some OS has injected #define min macros into their system headers) (via # 0x499602D2).
You're running into a name collision with std::min. It is likely included in one of the other standard libary headers that you included, either <iostream> or <string>, my guess is probably the latter. The quick fix is to rename your function. For example, renaming it to mymin works fine. Demo

STL error _without_ any STL in code

I am using gcc 3.4.4 on cygwin. I am getting this rather perplexing STL error message in my code below which does not use STL at all:
#include <iostream>
using namespace std;
const int N = 100;
bool s[N + 1];
bool p[N + 1];
bool t[N + 1];
void find(const bool a[], bool b[], bool c[]){
return;
}
int main(){
find(s, p, t);
return 0;
}
When I compile with
g++ stack.cc
I get the following error message:
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h: In function `_RandomAccessIterator std::find(_RandomAccessIterator, _RandomAccessIterator, const _Tp&, std::random_access_iterator_tag) [with _RandomAccessIterator = bool*, _Tp = bool[101]]':
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:314: instantiated from `_InputIterator std::find(_InputIterator, _InputIterator, const _Tp&) [with _InputIterator = bool*, _Tp = bool[101]]'
stack.cc:18: instantiated from here
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:207: error: ISO C++ forbids comparison between pointer and integer
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:211: error: ISO C++ forbids comparison between pointer and integer
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:215: error: ISO C++ forbids comparison between pointer and integer
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:219: error: ISO C++ forbids comparison between pointer and integer
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:227: error: ISO C++ forbids comparison between pointer and integer
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:231: error: ISO C++ forbids comparison between pointer and integer
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_algo.h:235: error: ISO C++ forbids comparison between pointer and integer
As you can see, the code does not use any STL at all, so this is rather strange. Also, the error disappears if I remove the line
using namespace std;
which hints at some namespace clash. It also disappears if I remove the const keyword from the definition o the function find.
On the other had the error also disappears (and this is rather surprising) if I make find a 2-argument function as follows:
#include <iostream>
using namespace std;
const int N = 100;
bool s[N + 1];
bool p[N + 1];
bool t[N + 1];
void find(const bool a[], bool b[]){
return;
}
int main(){
find(s, p);
return 0;
}
I can't imagine what could be the reason why find can be a two argument function but not a three argument one.
So here is a brief summary of the three ways to remove the error:
Remove the using namespace std; line.
Remove the const keyword from the definition of find.
Remove the third argument of the function find.
I cannot think of any logical reason why such an error should happen in the first place, and why it should get removed i I use any of the above seemingly completely unrelated steps. Is this a documented g++ bug? I tried searching for it, but honestly I was at a loss what to search for, and the few keywords I tried ("STL error without STL use") didn't turn up anything.
You simply have a collision, because you've unintentionally pulled std::find (which takes 3 arguments) into the global namespace when you did using namespace std;. For whatever reason, your <iostream> is #include-ing <algorithm>, or one of the parts of its internal implementation (specifically, bits/stl_algo.h).
I can't explain why removing const makes it go away; perhaps it affects the order in which the compiler resolves overloads.
You are confusing the compiler with the version of find that is in the standard library (std::find), which has 3 parameters, but not the ones you have.
If your code was in its own namespace, you could avoid this problem. Or by renaming your find method, or the solutions you have already documented.

G++ abs() on a short int appears to turn it into a double?

The following code does not compile if std::abs(angle) is present. The type of angle is in this case a short int.
template <class T>
typename T::storage_t::single_t FastSin(const typename T::storage_t::double_t &angle) {
const int B = (sizeof(typename T::storage_t::single_t)*8) - 2;
return (angle<<1) - ((angle*(std::abs(angle)))>>B);
}
A close look at the messages can verify that angle is in fact a short int. However, if I am reading the error correctly, GCC turns it into a double.
math.hpp: In function ‘typename T::storage_t::single_t FastSin(const typename T::storage_t::double_t&) [with T = Fixed<_t<signed char, short int> >, typename T::storage_t::single_t = signed char, typename T::storage_t::double_t = short int]’:
vector.hpp:106:30: instantiated from ‘void Vector2<T>::FastRotate(const single_t&) [with T = Fixed<_t<signed char, short int> >, Vector2<T>::single_t = signed char]’
test.cpp:9:18: instantiated from here
math.hpp:11:52: error: invalid operands of types ‘__gnu_cxx::__enable_if<true, double>::__type {aka double}’ and ‘const int’ to binary ‘operator>>’
What is going on here? Even return (angle<<1) - ((angle*(std::abs<int>(angle)))>>B); does the same.
I am using gcc version 4.6.1. The only external headers included are <cmath> and <cstdint>. The compilation flags are -std=c++0x -Wall.
abs() is not a template, but a set of overload functions. According to the standard, the overload for int, long, float, double, long double should exist. But the overload for short does not exist. But as the conversion sequence from short to int is only a promotion, and the conversion sequence form short to the other overloaded types are all conversions, the overload for int should be selected.
But in g++ (version 4.5.2 for me), a non-standard template is added to cmath:
template<typename _Tp>
inline typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
double>::__type
abs(_Tp __x)
{ return __builtin_fabs(__x); }
This template would take all built-in integral types other than int and long and give a return value of double.
As a matter of fact, using type unsigned int also produces this error in g++:
#include <cstdlib>
#include <cmath>
int main() {
unsigned int i,j;
i=0;
j=std::abs(i)>>2;
return 0;
}
Explicitly casting it to int (std::abs((int)i);) should solve this problem.
The std::abs() function isn't a template in C++; there are just several overloads provided for different types. The ones for the integral types are in the header <cstdlib>. See http://www.cplusplus.com/reference/clibrary/cstdlib/abs/ and http://www.cplusplus.com/reference/clibrary/cmath/abs/ for more info.
I know that this post is already answered long ago, but i just want to give another perspective which should help someone else. My problem was with QT and mingw, always when i build with boost or some other libraries which use cmath and cstdlib i got this error. After some time i was pretty annoyed with this error, and i decided to do a little research about those two files.
I totally agree with fefe and his answer but that can only solve problems if you use it in you program or library ,and you know from a start what is a problem, and that wasn't my problem.
If you really need to include both files in same time (you need system, malloc... and all math functions) quick and dirty fix is to open header and on 106 line (on my computer) you will see something like this:
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
using ::div_t;
using ::ldiv_t;
using ::abort;
//using ::abs;
using ::atexit;
using ::atof;
using ::atoi;
using ::atol;
using ::bsearch;
using ::calloc;
.
.
.
From code above you can see that cstdlib have function abs in std namespace and you need to comment that line in order to enable use of cmath abs function and to get rid of that nasty error.
I hope that this will help someone, and i am sorry for such a long post.