Вам необходимо переместить реализацию operator<<
в то же пространство имен, что и ваш класс. Он ищет:
ostream& operator<< (ostream& os, const skg::Triplet<T>& p_t)
Но не найдет его из-за кратковременного поиска в зависимости от аргументов (ADL). ADL означает, что когда вы вызываете свободную функцию, она будет искать эту функцию в пространствах имен своих аргументов. Это та же самая причина, по которой мы можем сделать:
std::cout << "Hello" << std::endl;
Даже если operator<<(std::ostream&, const char*)
находится в пространстве имен std
. Для вашего звонка эти пространства имен: std
и skg
.
Это будет смотреть в обоих случаях, а не искать в skg
(так как ваш находится в глобальной области видимости), затем искать в std
. Он увидит возможности (все нормальные operator<<
), но ни одна из них не совпадает. Поскольку выполняющийся код (код в ostream_iterator
) находится в пространстве имен std
, доступ к глобальному пространству имен полностью закрыт.
Поместив вашего оператора в то же пространство имен, ADL работает. Об этом говорится в статье Херба Саттера: «Скромное предложение: исправление ADL.» . (PDF). Фактически, вот фрагмент из статьи (демонстрирующий недостаток):
// Example 2.4
//
// In some library header:
//
namespace N { class C {}; }
int operator+( int i, N::C ) { return i+1; }
// A mainline to exercise it:
//
#include <numeric>
int main() {
N::C a[10];
std::accumulate( a, a+10, 0 ); // legal? not specified by the standard
}
Та же ситуация, что и у вас.
Книга Саттера и Александреску "Стандарты кодирования C ++" содержит полезное руководство:
- Храните тип и интерфейс функции, не являющийся членом, в одном и том же пространстве имен.
Следуйте за ним, и вы и ADL будете счастливы. Я рекомендую эту книгу, и даже если вы не можете ее получить, хотя бы прочитайте PDF-файл, который я ссылался выше; он содержит необходимую информацию.
Обратите внимание, что после перемещения оператора вам понадобится директива друга (чтобы вы могли получить доступ к приватным переменным):
template <typename U>
friend ostream& operator<< (ostream& os, const Triplet<U>& p_t);
И та-да! Исправлено.