Шаблонно-зависимый поиск - PullRequest
2 голосов
/ 20 апреля 2011

При компиляции этой программы я ожидал, что вызов оператора << преобразуется в глобальное пространство имен, но вместо этого компилятор сообщает о неоднозначной перегрузке. Я думал, что независимый поиск произошел до функций в пространствах имен, которые включены как потенциальные совпадения из-за аргументно-зависимого поиска. Похоже, что это относится к не шаблонным функциям. </p>

Может кто-нибудь объяснить?

#include <iostream>

class Foo
{};

namespace NS
{
    class Stream
    {};

    template <typename T>
    Stream& operator << ( Stream& s, T t)
    {
        std::cerr << "Namespace call!\n";
        return s;
    }
}

template<typename STREAM>
STREAM& operator << ( STREAM& s, Foo f )
{
    std::cerr << "Global NS call";
    return s;
}

/**
* This function (as opposed to the one above) is not ambiguous.  Why?

NS::Stream& operator << ( NS::Stream& s, Foo f )
{
    std::cerr << "Global NS call";
    return s;
}

*/

int main()
{
    Foo f;
    NS::Stream s;

    s << f;
    return 0;
}

Выход компилятора:

test11.cpp: In function ‘int main()’:
test11.cpp:28: error: ambiguous overload for ‘operator<<’ in ‘s << f’
test11.cpp:18: note: candidates are: STREAM& operator<<(STREAM&, Foo) [with STREAM = NS::Stream]
test11.cpp:13: note:                 NS::Stream& NS::operator<<(NS::Stream&, T) [with T = Foo]

Ответы [ 4 ]

3 голосов
/ 20 апреля 2011

Есть два возможных кандидата на s << f: глобальный и один для пространства имен.Нет ничего, чтобы выбирать между этими двумя для компилятора C ++, поэтому это неоднозначно.

1 голос
/ 04 января 2015

Несмотря на то, что это старый вопрос, я думаю, что есть некоторые вещи, которые не были прояснены в отношении конкретных вопросов ОП, поэтому здесь мы идем.

Прежде всего: поиск, зависящий от аргумента, иобычный неквалифицированный поиск и выполняется для неквалифицированных вызовов функций и операторов.Это относится как к обычным функциям, так и к специализациям шаблонов функций.В соответствии с [3.4.2 параграфом 3] единственными исключениями являются случаи, когда обычный неквалифицированный поиск находит:

  • объявление члена класса или
  • объявление функции блочной области видимости, котороене является объявлением использования или
  • объявлением, которое не является ни функцией, ни шаблоном функции.

Только в вышеприведенных случаях поиск, зависящий от аргумента, не выполняется.Как видите, ни один из них не применим в этом случае.

Итак, оба объявления найдены.Теперь необходимо выполнить разрешение перегрузки, чтобы выбрать наилучшую жизнеспособную функцию .Аргументы идеально соответствуют типам параметров в обоих случаях, поэтому одну перегрузку нельзя выбрать другой, исходя из лучших преобразований.Оба являются специализациями шаблонов, поэтому, в крайнем случае, частичное упорядочение шаблонов функций используется, чтобы попытаться определить, является ли один более специализированным , чем другой.Увы, шаблон в NS более специализирован для первого аргумента, а глобальный более специализирован для второго аргумента, поэтому ни один шаблон не является более специализированным, чем другой.Вывод: никакая перегрузка не может быть выбрана другим, вызов неоднозначен.

Теперь, для вашего второго вопроса, относительно определения оператора, которое закомментировано.Если вы раскомментируете это определение, в этом случае также выполняется ADL; все три перегрузки найдены по имени поиска.Опять же, все аргументы полностью соответствуют типам параметров.Отличие состоит в том, что последнее определение - это обычная операторная функция, а не шаблон.Если никакая перегрузка не может быть выбрана среди других на основе преобразований, то, если одна является нормальной функцией, а все остальные являются специализациями шаблона, предпочтение не шаблону по сравнению с другими.Вот почему в этом случае вызов больше не является двусмысленным.


Стандартные ссылки на N4140, последний черновик C ++ 14 перед публикацией, но я не думаю, что что-либо из вышеперечисленного изменилось после C++ 03.

1 голос
/ 20 апреля 2011

Глобальное пространство имен не имеет особого приоритета.Проблема с s << f состоит в том, что оба аргумента связаны с пространством имен: s с ::NS и f с ::.

Учитывая, что глобальное пространство имен имеетКак и любой другой (за исключением того, что он всегда находится в области видимости, что здесь не имеет значения), две перегруженные функции точно связаны для лучшего соответствия, и компилятор ничего не может сделать.

При использовании библиотеки IOStreamsэта проблема решается путем принятия параметров типа istream & или ostream & без параметризации шаблона.

0 голосов
/ 20 апреля 2011

Существует двусмысленность, потому что вы определили Stream внутри namespace NS.Если вы определите Stream в глобальном пространстве имен, то двусмысленности не будет.

Компилятор попытается определить, какую функцию выбрать в соответствии с аргументами неквалифицированной функции и связанными с ними пространствами имен.См. Раздел 3.4.2 - Поиск имени в зависимости от аргумента стандарта ISO / IEC 14882: 2003.Так как один аргумент определен в глобальном пространстве имен, а один аргумент определен в NS, компилятор не знает, какую функцию использовать.

...