1

The title of the question does not reveal too much about my problem but I tried to explain the problem in a single phrase. Here is the problem, I have a similar code structure in an application compiled with MinGW in Windows and GCC in Linux. Visual Studio doesn't present any problem. The structure is as follows:

#include <iostream>

namespace idb
{
    class Wrapper
    {
    public:
        template<typename S>
        void boo(S& s)
        {
            bind(s);
        }
    };
}

namespace idb // <- if this namespace changes, code explodes
{
    struct Fulalas
    {
        int x;
    };
}

namespace idb
{
    void bind(idb::Fulalas f)
    {
        std::cout << f.x << std::endl;
    }
}

namespace app
{
    class Foo
    {
    public:
        void func()
        {
            idb::Fulalas f;
            f.x = 5;
            w.boo(f);
        }

    private:
        idb::Wrapper w;
    };
}

int main()
{
    app::Foo f;
    f.func();
    return 0;
}

The question is why in GCC/MinGW changing idb::Fulalas to aaa::Fulalas (or any name desired) generates the following error:

..\namespace\main.cpp: In instantiation of 'void idb::Wrapper::boo(S&) [with S = aaa::Fulalas]':
..\namespace\main.cpp:41:11:   required from here
..\namespace\main.cpp:11:10: error: 'bind' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
    bind(s);
          ^
..\namespace\main.cpp:26:7: note: 'void idb::bind(aaa::Fulalas)' declared here, later in the translation unit
  void bind(aaa::Fulalas f)
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
McLeary
  • 1,231
  • 2
  • 13
  • 21

2 Answers2

5

It's not about the struct.

It's about bind and Argument Dependent Lookup.

bind is used unqualified and hence it's being looked for in associated namespaces. If the struct is not in the same namespace as that bind overload, then it will not be seen/considered.

Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
  • You answer a question unrelated to Boost?! – Columbo Dec 30 '14 at 19:34
  • This has nothing todo with boost. Bind is just an example function name I gave. – McLeary Dec 30 '14 at 22:15
  • Very good and simple answer @sehe. Do you have a clue why this works fine in Visual Studio 2013? – McLeary Dec 30 '14 at 22:17
  • 2
    @McLeary Yes. MSVC is a famously broken compiler with respect to 2-phase lookup implementation (meaning that anywhere near templates, which is... always, you can depend on name lookup being wonky). Most of the time you get "more" lookup candidates than you "legally" should according to the standard, so it's not often a problem, but you can run into portability issues. – sehe Dec 30 '14 at 23:06
  • @sehe: Personally I think that MSVC's model makes more sense than 2-phase, so I wouldn't describe it as "wonky", but non-conforming certainly. – Puppy Dec 30 '14 at 23:14
2

In the expression

bind(s)

the name bind is dependent because the argument s is of type S which is a template parameter. A dependent name is bound at the point of template instantiation. This occurs when you call

w.boo(f);

and thus instantiate boo with the type S = idb::Fulalas. When a dependent name is resolved, declarations are considered from two sources:

  • Declarations that are visible at the point of definition of the template.
  • Declarations from namespaces associated with the types of the function arguments both from the instantiation context (14.6.4.1) and from the definition context.

([temp.dep.res])

Therefore, if a name is declared after the point of definition of the template but before the point of instantiation, then it can only be found by ADL, not by ordinary unqualified name lookup. Ordinary unqualified lookup can only find names that are visible at the point of definition of the template, not at the point of instantiation. Therefore, if Fulalas is not declared in the same namespace as bind, ADL will not find the declaration of idb::bind and name lookup will fail altogether.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312