Вызов функции-члена шаблона с существующим именем

см. следующий код:

namespace std {
    template <std::size_t I, class T>
    auto& get(my_tuple_like_type<T>& t)
    {
        std::size_t ext = t.template extent<I>(); // This line
        // .... do something with ext and return
    }
}

Как видите, я пытаюсь специализировать (перегрузить) std::get, чтобы сделать свой собственный шаблон класса my_tuple_like_type несколько похожим на std::tuple.

Но gcc 5.4.0 жалуется, что константа I не является именем типа. Кажется, причина в том, что уже есть имя std::extent, которое является шаблоном класса.

Обходной путь, который я могу придумать, - перенаправить вызов автономной функции реализации, объявленной вне namespace std. Но мне интересно, это правильное поведение в соответствии со стандартом? Или это просто еще одна ошибка gcc?

Я предполагаю, что это должно быть ошибкой, так как clang и MSVC прекрасно компилируют приведенный выше код. С другой стороны, компилятор Nvidia CUDA (nvcc) выдает аналогичное сообщение об ошибке.

Спасибо.

ИЗМЕНИТЬ:

Предоставление перегрузок внутри namespace std запрещено (Должны ли вы перегружать swap в пространстве имен std?), значит, я поступил неправильно.

Но я не вижу потенциальных проблем, которые это может вызвать. Есть ли причина, по которой перегрузки пользовательских типов запрещены?


person Junekey Jeon    schedule 26.04.2017    source источник
comment
Почему вы нарушаете std? Для этого официально оставляет вашу программу с неопределенным поведением. Вы должны поместить свой класс в пространство имен, добавить функцию my_namesapce::get и позволить ADL сделать все остальное.   -  person StoryTeller - Unslander Monica    schedule 26.04.2017
comment
@StoryTeller AFAIK, специализация шаблонов в стандартном формате по отношению к моему собственному типу - это нормально. Например, std::iterator_traits даже предназначен для пользователей, не так ли?   -  person Junekey Jeon    schedule 26.04.2017
comment
@JunekeyJeon Я собирался ответить StoryTeller то же самое, но на самом деле это перегрузка, а не специализация, так что действительно UB.   -  person Quentin    schedule 26.04.2017
comment
@Quentin Хм, но тогда невозможно настроить поведение std::get при работе с определяемыми пользователем шаблонами классов, поэтому я думаю, что это должно быть разрешено ..., и я не думаю, что стандарт действительно запрещал это.   -  person Junekey Jeon    schedule 26.04.2017
comment
@JunekeyJeon — это сильно запрещает. Добавление перегрузки относится к добавлению определений. Специализация — это другой зверь.   -  person StoryTeller - Unslander Monica    schedule 26.04.2017
comment
Это запрещено, потому что разработчикам стандартных библиотек может потребоваться ввести вспомогательные классы/функции для реализации стандартного поведения. И комитет по стандартизации не хочет ограничивать их в реализации хороших чистых и эффективных реализаций. За исключением общедоступных имен, определенных для nameapce std, все другие идентификаторы внутри зарезервированы для разработчиков.   -  person StoryTeller - Unslander Monica    schedule 26.04.2017
comment
@JunekeyJeon - хитрость в том, чтобы не перегружать функцию шаблона в пространстве имен std. Посмотрите, сможете ли вы получить нужное вам поведение с помощью std::tuple вместо реализации собственного типа кортежа. Таким образом, среди прочего, вам не нужно возиться с попытками перегрузить функцию из пространства имен std.   -  person Peter    schedule 26.04.2017
comment
@StoryTeller Большое спасибо, но я не могу понять, как то, что вы сказали, связано с предотвращением предоставления перегрузок для пользовательских типов.   -  person Junekey Jeon    schedule 26.04.2017
comment
@JunekeyJeon - потому что вы не можете знать, использует ли разработчик свои собственные my_tuple_like_type в какой-либо форме или форме, или как имена в вашей реализации будут разрешаться внутри пространства имен std (именно поэтому возникает ваша ошибка, кстати).   -  person StoryTeller - Unslander Monica    schedule 26.04.2017
comment
@StoryTeller Хорошо, я понимаю, что что-то может пойти не так с неквалифицированными идентификаторами, но как насчет полных идентификаторов? И мне до сих пор неясно, правильно ли преобразовать extent в t.template extent<I> в std::extent... Что произойдет, если я заменю std на какое-то другое пространство имен, содержащее шаблонный класс extent? GCC по-прежнему считает, что extent не является членом t....   -  person Junekey Jeon    schedule 26.04.2017