Ответ 1
Короткий ответ:
Не удается найти правильный шаблон operator==
, в первую очередь, из-за того, что Google Test определяет собственный шаблон operator==
, а правило поиска пространства имен, которое не использует ADL, выбирает этот шаблон и отклоняет его. ADL, как указал Amadeus, не может надеяться найти шаблон, который я определил.
Решение:
Как указывает Amadeus, перемещение объектов в пространство имен std
(в данном случае для работы ADL) не рекомендуется.
У меня нет проблем с загрязнением пространства имен Google Test, поэтому перемещение моего шаблона в ::testing::internals
решает проблему (используя обычный поиск, а не ADL).
Более длинный ответ:
Я ожидал, что глобальный operator==
должен быть обнаружен через Vandevoorde и Josuttis, С++ Templates. Раздел 9.2, p. 122, термин обычный поиск.
Вот код, иллюстрирующий это:
#include <vector>
#include <deque>
template< typename T>
bool operator==( const std::vector<T>& v , const std::deque<T>& d);
namespace A {
template <typename T1, typename T2>
bool EQ( const T1& expected, const T2& actual ) {
return expected == actual;
}
}
void TestBody() {
std::vector<char> vec;
std::deque<char> deq;
::A::EQ(vec, deq) ;
}
Это успешно скомпилируется. Мое чтение ответа Амадеуса заключается в том, что Амадеус полагает, что он должен потерпеть неудачу из-за ADL. Однако в этом случае ADL не используется для поиска operator==
. Это можно продемонстрировать, явно отключив ADL при вызове оператора, переписав
expected == actual
а
return (operator==)( expected, actual);
V & J Раздел 9.2.1, стр .123:
ADL также запрещен, если имя вызываемой функции заключено в круглые скобки
и в этом случае код все еще компилируется.
Чтобы определить, почему код, связанный с Google Test, не удался, я сделал довольно экстремальную операцию в заголовках Google Test, пока не извлек только код, вызывающий ошибки компилятора, что привело к определению operator==
в testing::internal
пространство имен в gtest/internal/gtest-linked_ptr.h
:
namespace testing {
namespace internal {
[...]
template<typename T> inline
bool operator==(T* ptr, const linked_ptr<T>& x) {
return ptr == x.get();
}
[...]
}
}
Перевод этого кода в мой тестовый код приводит к:
#include <vector>
#include <deque>
template< typename T>
bool operator==( const std::vector<T>& v , const std::deque<T>& d);
namespace A {
struct S {};
template<typename T> bool operator==(T* ptr, S& x);
template <typename T1, typename T2>
bool EQ( const T1& expected, const T2& actual ) {
return expected == actual;
}
}
void TestBody() {
std::vector<char> vec;
std::deque<char> deq;
::A::EQ(vec, deq) ;
}
Это успешно не удается скомпилировать с ошибками неправильного шаблона. Представляет интерес первое сообщение об ошибке:
gtst.cc: In instantiation of ‘bool A::EQ(const T1&, const T2&) [with T1 = std::vector<char>; T2 = std::deque<char>]’:
gtst.cc:25:21: required from here
gtst.cc:14:37: error: no matching function for call to ‘operator==(const std::vector<char>&, const std::deque<char>&)’
gtst.cc:14:37: note: candidates are:
gtst.cc:10:31: note: template<class T> bool A::operator==(T*, A::S&)
gtst.cc:10:31: note: template argument deduction/substitution failed:
gtst.cc:14:37: note: mismatched types ‘T*’ and ‘std::vector<char>’
Итак, он сначала смотрит на A::operator==
.
Stroustrup, язык программирования С++, 4-е издание, раздел 26.3.5 с. 753 говорится, что привязка зависимых имен выполняется путем просмотра
- Имена в области в точке, где указан шаблон, плюс
- имена в пространстве имен аргумента зависимого вызова
В этом случае по первому правилу следует выбрать A::operator==
, а не ::operator==
. ADL также не находит ::operator==
, потому что, как указывает Amadeus, он не находится в пространстве имен std
.
Чтобы убедиться, что сбой компиляции действительно является результатом первого правила, я переместил определение ::operator==
в пространство имен A
и выключил ADL, как и раньше.
Код успешно компилируется.