Компилятор не может найти перегрузку - PullRequest
1 голос
/ 21 января 2020

Я недавно работал с некоторыми простыми типами для некоторого кода, который у меня есть, и перегружал оператор вставки для них, чтобы их можно было легко распечатать. Я натолкнулся на случай, когда я буквально получил тысячу строк компиляции. Упрощенная версия здесь:

#include <iostream>
#include <sstream>
#include <utility>
#include <string>

namespace ns{
template<typename KEY, typename VALUE>
using KeyValue = std::pair<KEY, VALUE>;

template<typename K, typename V>
inline std::ostream& operator<< (std::ostream& os, const KeyValue<K,V>& arg){
  os << "Key: " << arg.first << " Value: " << arg.second;
  return os;
}
}


struct Foo_t{
  double a = 0;
};

inline std::ostream& operator<< (std::ostream& os, const Foo_t& f){
  os << "a: " << f.a;
  return os;
}



int main()
{
  Foo_t foo{6.283185};
  ns::KeyValue<std::string, Foo_t> foo_kv{"Foo_t", foo};

  std::ostringstream oss;
  oss << foo_kv;

  std::cout << oss.str();
}

Оказывается, ошибка в том, что Foo_t и его operator<< не находятся в пространстве имен ns. Если я добавлю их в пространство имен ns и внесу коррективы в main, то все будет хорошо. Исходя из своего, по общему признанию, ограниченного знания, я бы подумал, что его найдут через ADL, но, похоже, это не так. Почему? Есть ли лучший способ исправить это, кроме простого добавления Foo_t в пространство имен ns?

Между прочим, тысяча строк puke компилятора была G CC, пытающейся помочь и перечисляющей все возможные перегрузки operator<<, о которых она знала.

1 Ответ

2 голосов
/ 21 января 2020

KeyValue - псевдоним для std::pair. Пространство имен, в котором определен шаблон псевдонима, не рассматривается как связанное пространство имен для ADL. Будет рассматриваться только класс и включающая область имен пространства самого класса std::pair.

Поэтому перегрузка оператора внутри ns не найдена.

Это равно найдено, если вы переместили Foo_t внутрь ns, поскольку область действия класса и включающая область пространства имен аргументов шаблона типа в типах аргументов функции учитываются для ADL.

Если Foo_t находится внутри ns, тогда ns будет добавлено в список связанных областей, в которых будет производиться поиск, поскольку это аргумент шаблона типа типа foo_kv. Если Foo_t объявлено в глобальной области пространства имен, то добавляется только глобальная область пространства имен (которая в любом случае уже ищется неквалифицированным поиском).

Что касается того, как это исправить: Если вы хотите перегрузку оператора независимо от того, какие аргументы шаблона используются, вы можете сделать KeyValue отдельным типом:

template<typename KEY, typename VALUE>
struct KeyValue : std::pair<KEY, VALUE> {
    using std::pair<KEY, VALUE>::pair;
};

или переместить перегрузку оператора в глобальное пространство имен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...