c++c++11qtest

Global function recognition failing


When having a simple qtest which compares 2 different objects for a user-defined struct:

Test a, b = {1};
QCOMPARE(a, b);

Why is there a difference between:

(1)

static char* toString(const Test &)
{
    using QTest::toString;
    return toString("Test");
}

And

(2)

namespace {

char* toString(const Test &)
{
    using QTest::toString;
    return toString("Test");
}

} // unnamed namespace

The first one does call the function when comparing the objects, the second one does not!

As mentioned in this conclusion, there should be no difference except anonymous namespaces allow you to define translation-unit-local type. Well, here it looks like it's the opposite.


Solution

  • The default QTest::toString implementation is a function template:

    template <class T> char *QTest::toString(const T &value);
    

    Specializing this template seems to be one way to provide a custom implementation, but you are using the other one, i.e., adding a function to the toString overload set. I haven't looked at the Qt sources, but it seems that the lookup for matching names to construct an overload set is performed using ADL.

    Now when you have this

    struct Test {};
    
    char *toString(const Test&);
    

    they are in the same (global) namespace. This works, because using ADL to look for names related to Test pulls in the global namespace, and that's where your toString overload resides. But that differs from

    struct Test {};
    
    namespace {
        char *toString(const Test&);
    }
    

    because the latter is identical to

    struct Test {};
    
    namespace someRandomUniqueIdentifier {
        char *toString(const Test&);
    }
    
    using namespace someRandomUniqueIdentifier;
    

    and hence when instantiating a function template for the type Test, ADL fails to find the toString name as Test is not declared in the (unnamed) someRandomUniqueIdentifier namespace. If you define Test inside the anonymous namespace, the appropriate toString function should be invoked.

    The thread you linked is about static functions vs. anonymous namespaces. The issue you encounter isn't related to that, it's the lookup rules, particularly ADL.