Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How avoid std naming conflicts due to Koenig lookup

As a learning exercise I've been reimplementing some of the STL algorithm. Even though I've not added any using directives or using declarations for the std namespace my test code won't compile unless I explicitly prefix those functions shadowing std names.

I assume that this is due to argument dependent lookup bringing in functions from the std namespace when I pass std::vector iterators as parameters to my functions.

A small program to illustrate my problem:

#include <vector>
#include <algorithm>

namespace danstd {
template <typename I, typename T>
I find(I b, I e, T val) {
    for (; b != e; ++b) {
        if (*b == val)
            return b;
    }
    return e;
}   
}

using namespace danstd;

int main() {
    std::vector<int> v = {1, 2, 3};

    auto i = find(begin(v), end(v), 3);
    return i == end(v) ? -1 : *i;
}

When I compile, I see these error messages:

$ g++ -Wall foo.cpp
foo.cpp: In function ‘int main()’:
foo.cpp:16:37: error: call of overloaded ‘find(std::vector<int>::iterator, std::vector<int>::iterator, int)’ is ambiguous
     return *find(begin(v), end(v), 3);
                                     ^
foo.cpp:5:3: note: candidate: I find(I, I, T) [with I = __gnu_cxx::__normal_iterator<int*, std::vector<int> >; T = int]
 I find(I b, I e, T val) {
   ^~~~
In file included from /usr/include/c++/6/algorithm:62:0,
                 from foo.cpp:2:
/usr/include/c++/6/bits/stl_algo.h:3784:5: note: candidate: _IIter std::find(_IIter, _IIter, const _Tp&)[with _IIter = __gnu_cxx::__normal_iterator<int*, std::vector<int> >; _Tp = int]
     find(_InputIterator __first, _InputIterator __last,
     ^~~~

In the unit test code, I've linked to above, I've wrapped my functions inside a danstd namespace and I make each call on the form danstd::function(...). Is there any way around having to use fully qualified names to avoid the naming conflicts with std names?

like image 319
Daniel Näslund Avatar asked Mar 08 '23 21:03

Daniel Näslund


2 Answers

I assume that this is due to argument dependent lookup bringing in functions from the std namespace when I pass std::vector iterators as parameters to my functions.

That is correct. Since std::vector::iterator lives in std it will do a lookup in std.

Is there any way around having to use fully qualified names to avoid the naming conflicts with std names?

Unfortunately no. You'll need to qualify you want the one from the global space like

return *::find(begin(v), end(v), 3);
like image 129
NathanOliver Avatar answered Mar 18 '23 04:03

NathanOliver


You can disambiguate the call as follows

return *::find(begin(v), end(v), 3);

Without that, the compiler is correct, the call is ambiguous as you've noted due to argument dependent lookup

like image 35
Cory Kramer Avatar answered Mar 18 '23 03:03

Cory Kramer