Я думаю, что на основе стандарта f
на самом деле не зависит.
14.6.2.2 Выражения, зависящие от типа [temp.dep.expr]
3 id-expression зависит от типа, если оно содержит
- идентификатор, связанный поиском имени с одним или несколькими объявлениями, объявленными с зависимым типом,
Это относится как к функции глобального шаблона, так и к функции шаблона-члена: никоим образом. Тип возвращаемого значения U
зависит от определений функций шаблона, но для вызывающего объекта тип функции f<int>
уже был преобразован из U(U)
в int(int)
. Во всяком случае, это не объясняет, почему компиляторы по-разному обрабатывают эти два случая, а также не объясняет, почему нешаблонные функции-члены также рассматриваются как зависимые.
- зависимый идентификатор шаблона,
- идентификатор функции преобразования, указывающий зависимый тип, или
Это не применимо. Не существует <
или >
, которые всегда должны присутствовать в идентификаторе шаблона, и нет вызываемой функции преобразования.
- описатель вложенного имени или полный идентификатор, который называет члена неизвестной специализации;
Смотри ниже.
или если он называет статический элемент данных текущего экземпляра, который имеет массив типов неизвестной границы T
для некоторого T
(14.5.1.3).
Это также не относится: здесь не задействованы никакие массивы.
Так что это зависит от того, является ли f
членом неизвестной специализации. Но это не так:
14.6.2.1 Зависимые типы [temp.dep.type]
5 Имя является членом неизвестной специализации, если оно
- квалифицированный идентификатор, в котором [...].
- квалифицированный идентификатор, в котором [...].
- id-expression, обозначающий член в выражении доступа к члену класса (5.2.5), в котором [...].
Они не могут применяться: f
не является ни квалифицированным, ни частью выражения доступа к члену класса.
Поскольку f
может быть зависимым только в том случае, если он является членом неизвестной специализации и не является членом неизвестной специализации, f
не должен быть зависимым.
На вопрос, почему компиляторы все же считают его зависимым, у меня нет ответа. Либо какая-то часть моего ответа здесь неверна, либо у компиляторов есть ошибки, либо компиляторы следуют другой версии стандарта С++. Тестирование на примере, который работает независимо от того, являются ли имена зависимыми, показывает несколько вариантов обработки компилятором:
#include <cstdio>
void f(const char *s, ...) { std::printf("%s: non-dependent\n", s); }
struct S1 { };
template <typename T>
struct S2 {
static S1 a;
static S1 b() { return {}; }
template <typename U>
static U c() { return {}; }
static void z() {
f("S1()", S1()); // sanity check: clearly non-dependent
f("T()", T()); // sanity check: clearly dependent
f("a", a); // compiler agreement: non-dependent
f("b()", b()); // compiler disagreement: dependent according to GCC 4.8, non-dependent according to clang
f("c<T>()", c<T>()); // sanity check: clearly dependent
f("c<S1>()", c<S1>()); // compiler agreement: dependent
f("decltype(b())()", decltype(b())()); // compiler agreement: dependent
}
};
void f(const char *s, S1) { std::printf("%s: dependent\n", s); }
// Just to show it's possible to specialize the members
// without specializing the full template.
template <>
S1 S2<S1>::b() { return {}; }
template <>
template <>
S1 S2<S1>::c<S1>() { return {}; }
int main() {
S2<S1>::z();
}
Эта разница в обращении clang с b()
, decltype(b())()
и c<S1>()
меня особенно беспокоит. Это просто не имеет никакого смысла. Очевидно, что все они одинаково зависимы. Я могу понять с точки зрения реализации, что нужно позаботиться о том, чтобы пока не генерировать код для функций-членов, потому что могут быть специализации S2<S1>::b
или S2<S1>::c<S1>
, но это относится ко всем и не влияет на тип возвращаемого значения. .
person
Community
schedule
27.12.2014
A::f
эквивалентноA<T>::f
, что может зависеть от параметра шаблонаT
. Так почему же это удивительно? - person Pradhan   schedule 27.12.2014A<T>
зависит, но также и текущая реализация означает, чтоA<T>::f
, следовательно, не является членом неизвестной специализации. - person willj   schedule 27.12.2014A::f
в другой специализацииA<T>
. - person 0x499602D2   schedule 27.12.2014A<T>
, это не может вызвать никакой разницы в значении везде, гдеf(0)
используется в неспециализированномA<T>
. - person   schedule 27.12.2014typename
запрещено? Это на самом деле невозможно, так как С++ 11. - person Columbo   schedule 27.12.2014