Является ли `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;
}