подкласс stringstream и nullptr - PullRequest
       23

подкласс stringstream и nullptr

0 голосов
/ 26 января 2019

Этот простой код может быть скомпилирован clang ++, но не с помощью g ++.Есть ли в нем что-то неопределенное?(функция шаблона необходима для того, чтобы сделать Clang счастливым) GCC 8.2.0 (используется с -std = c ++ 17) говорит, что оператор << неоднозначен, он показывает список кандидатов, но моей функции шаблона даже нет среди них.</p>

#include <cstddef>
#include <utility>
#include <sstream>

template<class Out>
Out&& operator<<(Out&& out, std::nullptr_t) {
  out << "nullptr";
  return std::forward<Out>(out); }

struct A : std::stringstream { };

int main() {
  A{} << nullptr;
}

1 Ответ

0 голосов
/ 26 января 2019

Я полагаю, что это вызвано Ошибка 51577 GCC.

Ваш код приводит к созданию std::__is_insertable<std::basic_ostream<char>&, std::nullptr_t&, void> в libstdc ++, тогда давайте посмотрим на определение этогоstruct :

template<typename _Ostream, typename _Tp, typename = void>
  struct __is_insertable : false_type {};

template<typename _Ostream, typename _Tp>
  struct __is_insertable<_Ostream, _Tp,
                         __void_t<decltype(declval<_Ostream&>()
                                           << declval<const _Tp&>())>>
                                  : true_type {};

Если все пойдет хорошо, ваш operator<< здесь невидим 1 , тогда частичная специализация отключена SFINAE , и__is_insertable обычно создается как производный класс std::false_type.

Теперь, из-за ошибки 51577, здесь отображается ваш operator<<, в результате чего специализация по родам идеально подходит.Однако при создании экземпляра __is_insertable ваш operator<< по какой-то причине невидим, поэтому возникает ошибка из-за неоднозначной перегрузки для operator<<.


Примечание GCC 9 компилируется этот кодЭто связано с тем, что в C ++ 17 добавлена ​​ новая перегрузка

basic_ostream& operator<<( std::nullptr_t );

..., поэтому можно успешно создать экземпляр __is_insertable независимо от того, виден ли ваш operator<<,Ошибка все еще есть.


1 Это потому, что [temp.dep.candidate] / 1 :

Для вызова функции, где postfix-выражение является зависимым именем, функции-кандидаты находятся с использованием обычных правил поиска ([basic.lookup.unqual], [basic.lookup.argdep]), за исключением того, что:

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

  • Для части поиска с использованием связанных пространств имен ([basic.lookup.argdep]), найдены только объявления функций, найденные либо в контексте определения шаблона, либо в контексте создания шаблона.

Ваш operator<< не может быть найден изконтекст определения шаблона, конечно.Аргументы имеют типы std::basic_ostream<char> и std::nullptr_t, поэтому связанные пространства имен не содержат глобального пространства имен.В результате ваш operator<< не должен быть найден.

...