Является ли имя нестатического члена зависимым при использовании в нестатической функции-члене?

Для 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

Выражения следующих форм никогда не зависят от типа (потому что тип выражения не может быть
зависимая):

sizeof unary-expression
[Temp.dep.constexpr] / 2

Выражения следующей формы зависят от значения, если унарное выражение или выражение зависит от типа
или идентификатор типа зависит:

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 быть зависимым?

15

Решение

Как правильно сказано вами, 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], который является простой шаблон-идентификатор с зависимыми аргументами шаблона.

2

Другие решения

Ответ зависит от того, 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

Если объявление объявляет функцию-член или шаблон функции-члена класса X, the expressionthis`
является значением типа «указатель на cv-qualifier-seq X» между необязательным cv-qualifer-seq и концом
определение функции, член-декларатор или декларатор. Он не должен появляться перед необязательным cv-qualifier-seq
и он не должен появляться в объявлении статической функции-члена (хотя ее тип и значение
категории определяются внутри статической функции-члена, так как они находятся внутри нестатической функции-члена).

[Expr.prim.general] / 5

Выражение 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

1

По вопросам рекламы [email protected]