Глобальное распознавание функции не удалось - PullRequest
4 голосов
/ 21 марта 2019

При наличии простого qtest, который сравнивает 2 разных объекта для определенной пользователем структуры:

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

Почему существует разница между:

(1)

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

И

(2)

namespace {

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

} // unnamed namespace

Первый вызывает функцию при сравнении объектов, второй нет!

Как уже упоминалось в этом заключении , не должно быть никакой разницы, кроме анонимных пространств имен, позволяющих определить тип translation-unit-local.Ну вот, похоже, все наоборот.

1 Ответ

2 голосов
/ 21 марта 2019

Реализация по умолчанию QTest::toString представляет собой шаблон функции:

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

Специализация этого шаблона, по-видимому, является одним из способов обеспечения пользовательской реализации, но вы используете другой способ, т. Е. Добавление функции к набору перегрузки toString. Я не смотрел на источники Qt, но кажется, что поиск подходящих имен для построения набора перегрузки выполняется с использованием ADL.

Теперь, когда у вас есть это

struct Test {};

char *toString(const Test&);

они находятся в одном (глобальном) пространстве имен. Это работает, потому что с помощью ADL для поиска имен, связанных с Test, тянет в глобальном пространстве имен, и именно здесь находится ваша перегрузка toString. Но это отличается от

struct Test {};

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

потому что последний идентичен

struct Test {};

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

using namespace someRandomUniqueIdentifier;

и, следовательно, при создании экземпляра шаблона функции для типа Test ADL не может найти имя toString, так как Test не объявлено в (неназванном) someRandomUniqueIdentifier пространстве имен. Если вы определяете Test внутри анонимного пространства имен, должна быть вызвана соответствующая функция toString.

Связанный вами поток о static функциях и анонимных пространствах имен. Проблема, с которой вы столкнулись, не связана с этим, это правила поиска, особенно ADL.

...