Search code examples
c++c++20argument-dependent-lookupname-lookup

ADL lookup not considering std for non-template function from within another namespace


I'm trying to add a custom to_string function for an enum class that can be found using ADL, since overloading std::to_string itself would be undefined behavior. I have the following code:

// -std=c++20
#include <string>
#include <iostream>
#include <cstdint>

namespace tns {
    enum class MyEnum : std::int32_t {};

    std::string to_string(MyEnum mine) {
        return std::to_string(static_cast<std::int32_t>(mine));
    }

    void test() {
        using namespace std;
        MyEnum mine{2};
        std::int32_t i = 1;
// (1)
        // error: no matching function for call to 'to_string'
        // note: candidate function not viable:
        //   no known conversion from 'std::int32_t' (aka 'int')
        //   to 'MyEnum' for 1st argument
        // std::cout << to_string(i);  // error
        std::cout << " " << to_string(mine) << '\n';
    }
}

void test2() {
    using namespace std;
    tns::MyEnum mine{2};
    std::int32_t i = 1;
// (2)
    std::cout << to_string(i);  // OK
    std::cout << " " << to_string(mine) << '\n';
}

int main() {
    tns::test();
    test2();
    return 0;
}

Why does the code at (1) in tns::test trigger a compiler error, but not the same code at (2) in ::test2? I have looked through the ADL rules but can't figure it out.


Solution

    1. With tns::to_string you hide the to_string in std that would otherwise be considered since you did using namespace std;. using namespace ... does not add all things in the used namespace into the current one.

      In order to make std::to_string come out of hiding, bring that overload into the tns namespace with

      using std::to_string;
      

      They now both participate in overload resolution when using to_string.

    2. Both to_strings are found in their respective namespace via ADL. None hides the other and they compete on equal terms so to speak.