Я полагаю, что это вызвано Ошибка 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<<
не должен быть найден.