Search code examples
c++compiler-errorsc++20header-files

Why must I specify the namespace of a global function when calling it from an identically-named member function in the same namespace?


I have three C++ files header1.h, header2.h, and main.cpp. They are below:

header1.h, which defines the function lerp in the namespace MyNamespace:

#ifndef HEADER_1_H
#define HEADER_1_H

namespace MyNamespace {

    template <typename T>
    inline float lerp(float t, T a, T b) {
        return (1 - t) * a + t * b;
    }

};

#endif

header2.h, which defines a class MyClass in MyNamespace, which has a member function called lerp, which calls the lerp from header1.h:

#ifndef HEADER_2_H
#define HEADER_2_H

#include "header1.h"

namespace MyNamespace {

    struct MyClass {
        float x, y, z;
    
        void lerp(float t) {
            x = lerp(t, x, 0.f);
             // ^^ This results in a compiler error (no matching function for
             // call to ‘MyNamespace::MyClass::lerp(float&, float&, float). Why?
             // Also, either prefixing this `lerp` with MyNamespace, or changing
             // the name of this member function to anything else that's not lerp,
             // stops the compiler error from occurring. Why?
        }
    };

};

#endif

main.cpp, which constructs an object of type MyClass and calls MyClass::lerp() on it:

#include "header2.h"

using namespace MyNamespace;

int main()
{
    MyClass mc{1, 2, 3};
    mc.lerp(4);  // results in a compiler error; see the comment in "header2.h"

    return 0;
}

When I try to compile main.cpp, I receive the following compiler error about my usage of lerp within the MyClass::lerp() function in header2.h:

header2.h: In member function ‘void MyNamespace::MyClass::lerp(float)’:
header2.h:12:17: error: no matching function for call to ‘MyNamespace::MyClass::lerp(float&, float&, float)’
   12 |         x = lerp(t, x, 0.f);
      |             ~~~~^~~~~~~~~~~
header2.h:11:10: note: candidate: ‘void MyNamespace::MyClass::lerp(float)’
   11 |     void lerp(float t) {
      |          ^~~~
header2.h:11:10: note:   candidate expects 1 argument, 3 provided

So, my first question is, why doesn't the compiler seem to be able to find the definition of MyNamespace::lerp() provided in header1.h? Shouldn't it be able to find it, because we are in the same namespace (MyNamespace) and because header2.h includes header1.h?

Also, I've observed that either explicitly qualifying lerp(t, x, 0.f) with MyNamespace, or by renaming the member function MyClass::lerp to anything else, the compiler error goes away. Why is this?


Solution

  • tldr Because unqalified name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.

    why doesn't the compiler seem to be able to find the definition of MyNamespace::lerp() provided in header1.h?

    Because when you wrote x = lerp(t, x, 0.f);, unqualified name lookup starts and finds the member function named lerp and so name lookup stops. Thus, the only candidate function is the member function named lerp. And since it is incompatible with the call arguments, we get the mentioned error.

    This can be seen from unqualified name lookup documentation:

    For an unqualified name, that is a name that does not appear to the right of a scope resolution operator ::, name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.