Для gcc 5.0 и clang 3.6 требуется typename
Ключевое слово в следующем примере:
template<int n>
struct I
{
typedef int Type;
};
template<typename T>
struct A
{
int m;
void f()
{
typedef typename I<sizeof m>::Type Type; // typename required
}
};
На это распространяется следующая формулировка в стандарте C ++ 11:
[Temp.dep.type] / 8Тип зависит, если он
- простой-шаблон-идентификатор, в котором либо имя шаблона является параметром шаблона, либо любым из шаблона
Аргументы являются зависимым типом или выражением, которое зависит от типа или значения
Так I<sizeof m>
зависит, если sizeof m
зависит от стоимости.
[Temp.dep.expr] / 4Выражения следующих форм никогда не зависят от типа (потому что тип выражения не может быть
зависимая):[Temp.dep.constexpr] / 2sizeof unary-expression
Выражения следующей формы зависят от значения, если унарное выражение или выражение зависит от типа
или идентификатор типа зависит:sizeof unary-expression
Так sizeof m
зависит только если m
зависит.
[Expr.prim.general] / 8В пределах
определение нестатической функции-члена, идентификатор которой именует нестатический член, преобразуется в
выражение доступа к члену класса
Так m
является членом в выражении доступа члена класса.
[Temp.dep.type] / 4Имя это член текущей инстанции если это
- Выражение id, обозначающее член в выражении доступа к члену класса (5.2.5), для которого тип
выражения объекта является текущим экземпляром, а выражение id — при поиске (3.4.5),
относится по меньшей мере к одному члену текущего экземпляра или его независимому базовому классу.
Так что кажется, что m
является членом текущего экземпляра.
[Temp.dep.type] / 5Имя является членом неизвестной специализации, если оно
Выражение id, обозначающее члена в выражении доступа к члену класса (5.2.5), в котором либо
тип выражения объекта является текущим экземпляром, текущий экземпляр имеет по крайней мере
один зависимый базовый класс, и поиск имени в выражении id не находит члена
текущий экземпляр или его независимый базовый класс; или жетип выражения объекта является зависимым и не является текущей реализацией.
Так m
НЕ является членом неизвестной специализации — он будет найден по имени поиска, чтобы быть членом текущей реализации.
[Temp.dep.expr] / 3Выражение id зависит от типа, если оно содержит
- идентификатор, связанный с поиском имени с одним или несколькими объявлениями, объявленными с зависимым типом,
- спецификатор вложенного имени или квалифицированный идентификатор, который называет члена неизвестной специализации
поскольку m
имеет тип int
и не является членом неизвестной специализации, ни одна из этих пуль не сделает id-выражение m
зависимый.
[Temp.dep.expr] / 5Выражение доступа к члену класса (5.2.5) зависит от типа, если выражение относится к члену текущего
создание экземпляра и тип ссылочного члена зависит, или выражение доступа члена класса
относится к члену неизвестной специализации.
когда m
преобразован в выражение доступа к члену класса, он все еще не зависит, потому что он не ссылается на члена неизвестной специализации.
Должен m
лечиться как зависимый? На связанной ноте, следует this->m
лечиться как зависимый? Как насчет std::declval<A>().m
?
РЕДАКТИРОВАТЬ
И, наконец, следует &A::m
быть зависимым?
Как правильно сказано вами, sizeof m
превращается в sizeof (*this).m
,
sizeof
зависит только в том случае, если выражение аргумента зависит от типа, а это не так, согласно [temp.dep.expr] / 5:
Выражение доступа к члену класса (5.2.5) зависит от типа, если
Выражение относится к члену текущего экземпляра и тому
тип ссылочного члена зависит, или доступ члена класса
Выражение относится к члену неизвестной специализации.
Тип m
не зависит, и выражение также не относится к члену неизвестной специализации — [temp.dep.type] / 6:
Имя является членом неизвестной специализации, если оно
- ID-выражение обозначение члена в выражении доступа к члену класса (5.2.5), в котором либо
- типом выражения объекта является текущий экземпляр, текущий экземпляр имеет как минимум один зависимый базовый класс, и
поиск имени ID-выражение не находит члена класса
это текущий экземпляр или независимый базовый класс
их; или же- тип выражения объекта является зависимым и не является текущей реализацией.
Хотя тип (*this)
зависит, это текущая реализация. И поиск имени должен найти m
быть участником текущей инстанции.
Так *this
не зависит от типа и, следовательно, sizeof (*this).m
не зависит (sizeof m
также не зависит от каких-либо нестатических инициализаторов членов данных определения функции, которые я случайно описал в своем втором удаленном ответе).
За sizeof std::declval<A>().m
быть зависимым, std::declval<A>().m
должен быть зависимым от типа.
std::declval<A>().m
кажется быть типозависимым, но я не уверен. Как указано в [temp.dep.expr] / 5, который я цитировал выше, единственная возможность состоит в том, что m
в выражении есть член неизвестной специализации, который мы должны показать это.
Имя является членом неизвестной специализации, если оно
- ID-выражение обозначение члена в выражении доступа к члену класса (5.2.5), в котором либо
- типом выражения объекта является текущий экземпляр, текущий экземпляр имеет как минимум один зависимый базовый класс, и
поиск имени в id-выражении не находит члена класса
это текущий экземпляр или независимый базовый класс
их; или же- тип выражения объекта является зависимым и не является текущей реализацией.
Вот факты:
Выражение объекта std::declval<A>()
зависит от типа.
Поиск из std::declval<A>
делается только в контексте определения, так как это Квалифицированный-идентификатор, которые никогда зависимые имена ([Temp.dep] / 1).
Есть ровно один declval
Шаблон функции найден путем поиска по квалифицированному имени, но мы не можем знать, является ли тип возвращаемого значения этого кандидата текущим экземпляром во время определения. Здесь, в частности, add_rvalue_reference
может иметь специализации, не известные во время определения (сценарий, аналогичный этот). Итак, потому что мы не знаем, std::declval<A>()
является текущей реализацией, (мы предполагаем), это не так, что делает все выражение зависимым от типа.
&A::m
имеет форму &
Квалифицированный-идентификатор, который покрывается [temp.dep.constexpr] / 5:
[Temp.dep.type] / 5:Выражение формы
&
Квалифицированный-идентификатор где Квалифицированный-идентификатор
называет зависимого члена текущего экземпляра
Значение-зависимое.
Имя это зависимый член текущего экземпляра если это
член текущего экземпляра, который при поиске ссылается на
хотя бы один член класса, который является текущим экземпляром.
очевидно A::m
является членом текущего экземпляра, таким образом &A::m
зависит от стоимости.
Также &A::m
зависит от типа: подвыражение A
эквивалентно A<T>
в соответствии с [temp.local], который является простой шаблон-идентификатор с зависимыми аргументами шаблона.
Ответ зависит от того, m
можно посмотреть, чтобы определить, что он является членом текущего экземпляра. Id-выражение m
преобразован в доступ к члену класса (*this).m
Это означает, что применимы правила поиска квалифицированного имени в пределах доступа члена класса.
Как правило, тип зависимого от типа выражения не может быть определен. Не совсем ясно, следует ли делать исключение для (*this).
а также this->
, Выражение, содержащее this
зависит от типа, но оба (*this).
а также this->
однозначно назовите текущий экземпляр.
m
Выражение m
действительно не зависит от типа, потому что относится к члену текущего экземпляра.
В контексте нестатического члена, m
превращается в выражение доступа члена класса (*this).m
,
[Class.mfct.non-статические] / 3Когда id-выражение (5.1), которое не является частью синтаксиса доступа к члену класса (5.2.5) и не используется для формирования указателя на член (5.3.1), используется в члене класса
X
в контексте, где это можно использовать (5.1.1), если поиск по имени (3.4) разрешает имя в выражении id в нестатический нетипичный член некоторого классаC
и если или id-выражение потенциально оценивается илиC
являетсяX
или базовый классX
, id-выражение преобразуется в выражение доступа к члену класса (5.2.5) с использованием(*this)
Преобразование происходит потому, что m
является членом класса A
используется внутри нестатического члена класса A
,
[Expr.prim.general] / 3Если объявление объявляет функцию-член или шаблон функции-члена класса
[Expr.prim.general] / 5X, the expression
this`
является значением типа «указатель на cv-qualifier-seq X» между необязательным cv-qualifer-seq и концом
определение функции, член-декларатор или декларатор. Он не должен появляться перед необязательным cv-qualifier-seq
и он не должен появляться в объявлении статической функции-члена (хотя ее тип и значение
категории определяются внутри статической функции-члена, так как они находятся внутри нестатической функции-члена).Выражение
this
не должно появляться ни в каком другом контексте. [ Пример:
class Outer {
int a[sizeof(*this)]; // error: not inside a member function
unsigned int sz = sizeof(*this); // OK: in brace-or-equal-initializer
void f() {
int b[sizeof(*this)]; // OK
struct Inner {
int c[sizeof(*this)]; // error: not inside a member function of Inner
};
}
};
— конец примера]
Приведенный выше пример явно разрешает использование this
в пределах sizeof
выражение в нестатическом члене.
[Temp.dep.expr] / 2
this
зависит от типа, если тип класса включающей функции-члена зависит
Следовательно this
зависит от типа в определении функции-члена шаблона класса.
[Temp.dep.expr] / 1За исключением случаев, описанных ниже, выражение зависит от типа, если любое подвыражение зависит от типа.
Тем не менее, вышеупомянутое отменяется исключением из [temp.dep.expr] / 5, приведенным в вопросе.
this->m
Выражение this->m
также не зависит от типа, потому что это также выражение доступа к члену класса, которое ссылается на член текущего экземпляра.
std::declval<A>().m
Выражение std::declval<A>().m
должен быть зависимым от типа, так как тип возвращаемого значения std::declval<A>()
может зависеть от типа A
,
[Temp.local] / 1Как и обычные (не шаблонные) классы, шаблоны классов имеют имя введенного класса (раздел 9). Инъекционный класс-
имя может использоваться как имя шаблона или имя типа. Когда он используется со списком аргументов шаблона,
в качестве аргумента шаблона для параметра шаблона шаблона или в качестве окончательного идентификатора в уточненном спецификаторе типов
объявления шаблона класса друга, оно ссылается на сам шаблон класса. В противном случае это эквивалентно
к имени шаблона, за которым следуют параметры шаблона шаблона класса, заключенного в<>
Следовательно A
превращается в A<T>
,
[Temp.dep.type] / 8Тип зависит, если он
параметр шаблона,
простой-шаблон-идентификатор, в котором либо имя шаблона является параметром шаблона, либо любым из шаблона
Аргументы являются зависимым типом или выражением, которое зависит от типа или значения
Это подтверждает, что A<T>
является зависимым типом, что означает, что A
также зависит.
[Temp.dep.expr] / 3Выражение id зависит от типа, если оно содержит
- идентификатор шаблона, который зависит,
Так std::declval<A>
является зависимым от типа выражением. Это следует из того std::declval<A>().m
зависит от типа, потому что содержит зависимое от типа подвыражение std::declval<A>
,
&A::m
Выражение &A::m
логически должен быть зависимым от типа, потому что он имеет тип int A<T>::*
который является зависимым типом.
Выражение &A::m
превращается в &A<T>::m
так как A
является введенным именем класса — как показано выше.
Id-выражение A<T>::m
зависит от типа в соответствии с [temp.dep.expr] / 3, потому что он содержит идентификатор шаблона A<T>
это зависит. Поэтому выражение &A<T>::m
зависит от типа в соответствии с [temp.dep.expr] / 1.
A::m
Выражение A::m
превращается в A<T>::m
так как A
является введенным именем класса — как показано выше. Выражение A<T>::m
далее преобразуется в (*this).A<T>::m
так как A<T>::m
называет нестатический член A
,
Id-выражение A<T>::m
зависит от типа в соответствии с [temp.dep.expr] / 3, потому что он содержит идентификатор шаблона A<T>
это зависит. Выражение доступа к члену класса (*this).A<T>::m
ссылается на член текущего экземпляра, поэтому [temp.dep.expr] / 5 применяется, но не делает выражение зависимым от типа — и не противоречит [temp.dep.expr] / 3.
Учитывая приведенную выше интерпретацию, id-выражение, именующее члена A
квалифицированный с A
или же A<T>
станет зависимым от типа, что кажется ненужным и противоречивым. Учтите, что имя типа уточняется A
или же A<T>
не будет зависеть в том же контексте.
Если намерение [temp.dep.expr] / 5 таково (*this).m
не зависит от типа, то из этого следует, что (*this).A<T>::m
также не должен зависеть от типа. С другой стороны, возможно, что имя нестатического члена всегда зависит. Я отправил вопрос на std-обсуждение, чтобы прояснить этот момент: https://groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/gEvZ7mmXEC8