Является ли `using Base:: operator T` разрешенным, где` T` является параметром типа шаблона?
Рассмотрим следующий пример:
struct B { operator int(); };
template<class T>
struct X:B
{
using B::operator T;
};
GCC принимает код, а Clang и MSVC отклоняет его.
Что правильно?
Обратите внимание, что если базовый тип зависит, все компиляторы принимают код:
template<class T>
struct B { operator T(); };
template<class T>
struct X:B<T>
{
using B<T>::operator T;
};
Ответы
Ответ 1
Я думаю, что GCC прав, в разделе 7.3.3/1 мы можем найти:
Набор деклараций, введенных с помощью объявления-объявления, определяется путем выполнения квалифицированного поиска имени (3.4.3, 10.2) для имени в объявлении использования, за исключением функций, которые скрыты, как описано ниже.
Я не вижу причин, по которым operator T
не будет найден, на самом деле:
template<class T>
struct X: B {
T f () { return B::operator T; }
};
... компилируется с g++ и clang (не тестировался на MSVC).
Я не могу найти ничего в стандарте, специфичном для функций преобразования для квалифицированного поиска имени, кроме:
Так как специализации шаблонов-членов для функций преобразования не найдены при поиске по имени, они не учитываются, когда декларация use указывает функцию преобразования (14.5.2).
Но B::operator int
не является специализацией шаблона функции-члена, поэтому он не должен учитываться выше.
Ответ 2
Хм... Gcc не нравится первый. Он компилируется, если вы не попытаетесь создать экземпляр struct X
с параметром шаблона, отличным от int
. В чем смысл X<double>::operator double()
? Класс B не имеет такого оператора, но мы бы попытались его использовать.
Подводя итог: MSVC и clang попытаются предупредить вас заранее (даже если вы сейчас ничего не делаете veeeery), а gcc создает ошибку, только если вы попытаетесь создать что-то неправильное. Это не компилируется в gcc (5.3.0):
#include <iostream>
struct B { operator int(); };
template<class T>
struct X:B
{
using B::operator T;
};
int main(int argc, char **argv)
{
X<char> x;
std::cout << "Hello!" << std::endl;
return 0;
}