Где стандарт C++98 указывает, когда вызов статического члена зависит от шаблона?
Компилируя с Clang 3.0 -std= C++98, следующий код принят:
template<int>
struct I
{
typedef int Type;
};
template<class>
struct S
{
static int f(int);
//static int f(int*);
// implicitly instantiates I<sizeof(int)>
typedef I<sizeof(f(0))>::Type Type;
};
S<int>::Type s;
Раскомментирование перегрузки "f" заставляет Clang сообщать об ошибке "отсутствует имя типа" до имени зависимого типа ". G++ 4.8 сообщает об одной и той же ошибке с перегрузкой или без нее. msvc10 не выдает ошибок с или без перегрузки.
Где в стандарте указано, является ли "f" зависимым и требуется ли "typename"? Если "typename" не требуется, где в стандарте указано, следует ли выполнять разрешение перегрузки в этом сценарии?
РЕДАКТИРОВАТЬ:
Для пояснения: причина, по которой я упоминаю разрешение перегрузки, заключается в том, что может потребоваться выполнить разрешение перегрузки, чтобы определить значение выражения константы 'sizeof(f(0)) ". Если (как я предполагаю) разрешение перегрузки не выполняется при определении того, является ли выражение зависимым от типа, значение константного выражения sizeof (f (0)) невозможно определить (во время анализа), когда зависимая перегрузка из 'f' существует: например
template<int>
struct I
{
typedef int Type;
};
template<class T>
struct S
{
static T f(int);
typedef typename I<sizeof(f(0))>::Type Type;
};
S<int>::Type t;
Компилируя с Clang 3.0 -std= C++98, это не выдает ошибок. Мне это кажется правильным, потому что стандарт считает выражение зависимым от типа, если оно является id-выражением, в котором указан объект, объявленный с зависимым типом.
3 ответа
Абзац стандарта C++98, который охватывает этот сценарий, находится в [temp.dep.expr]
Выражение id зависит от типа, если оно содержит:
- идентификатор, который был объявлен с зависимым типом,
Эта формулировка несколько расплывчата в отношении идентификаторов, которые перегружены и потенциально объявляются более чем одним типом, как сообщается в DR 541: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html
Это было решено (в более свежем проекте), изменив абзац следующим образом:
Выражение id зависит от типа, если оно содержит:
- идентификатор, связанный с поиском по имени с одним или несколькими объявлениями, объявленными с зависимым типом,
При рассмотрении следующего кода:
template<class T>
struct S
{
static int f(int);
static int f(int*);
static T g(int*);
static int g(int);
static const int x = sizeof(f(0));
static const int y = sizeof(g(0));
};
Моя интерпретация заключается в том, что идентификатор f
в выражении f(0)
не зависит, пока идентификатор g
в выражении g(0)
зависит.
При определении, является ли выражение вызова функции зависимым - хотя разрешение перегрузки не выполняется - учитываются все перегрузки функции.
Зависимые имена определены в 14.6.2. GCC жалуется на I<sizeof(f(0))>
будучи зависимым, давайте разберемся с этим.
14.6.2.1 последняя пуля:
идентификатор шаблона, в котором либо имя шаблона является параметром шаблона, либо любой из аргументов шаблона является зависимым типом или выражением, которое зависит от типа или значения
так sizeof(f(0))
должен быть зависимым от стоимости. 14.6.2.3p2:
Выражения следующей формы зависят от значения, если унарное выражение зависит от типа... sizeof unary-expression
поэтому мы зависим, если f(0) считается зависимым. (Небольшой эксперимент показывает, что gcc рассматривает член как функцию, зависимую от функции, так и функцию, не зависящую от нее.)
За исключением случаев, описанных ниже, выражение зависит от типа, если любое подвыражение зависит от типа.
И я не вижу ни зависимых от типа подвыражений, ни чего-либо значимого в списке исключений.
f
является членом S
, который является шаблоном, поэтому любое использование f
в S
зависит от параметров шаблона S
,
14.6.2.3 [temp.dep.constexpr] пункт 2:
Выражение id зависит от значения, если:
...
- он называет статическую функцию-член, которая является зависимым членом текущей реализации
Это относится к 'f' здесь, который является зависимым членом текущего экземпляра. 14.6.2.1 [temp.dep.types] пункт 4:
...
Имя является зависимым членом текущего экземпляра, если оно является членом текущего экземпляра, который при поиске ссылается по крайней мере на один член класса, являющегося текущим экземпляром.
как следствие sizeof(f(0))
зависит, I<sizeof(f(0))>
зависит, и I<sizeof(f(0))>::Type
потребности typename
идентифицировать его как тип, а не элемент данных.
Следовательно, GCC имеет право жаловаться.
MSVC делает поздний поиск по шаблонам, поэтому не жалуется. Это ошибка, но я не думаю, что они когда-либо собираются ее исправить.
Clang, кажется, здесь есть ошибка.