2016-01-21 3 views
7

Я пытаюсь понять последовательность в ошибке, выбрасываемая в этой программе:Указатель на член спутанности

#include <iostream> 

class A{ 
public: 
    void test(); 
    int x = 10; 

}; 

void A::test(){ 

    std::cout << x << std::endl; //(1) 
    std::cout << A::x << std::endl; //(2) 

    int* p = &x; 
    //int* q = &A::x; //error: cannot convert 'int A::*' to 'int*' in initialization| //(3) 


} 

int main(){ 

    const int A::* a = &A::x; //(4) 

    A b; 

    b.test(); 

} 

Выход 10 10. Я меченый 4 пункта программы, но (3) моя самая большая забота:

  1. x забирается обычно внутри функции-члена.
  2. x объекта извлекается с использованием оператора области действия и возвращается значение lvalue к объекту x.
  3. Учитывая A::x возвратила int именующее выражение в (2), то почему же тогда &A::x возвращение не int*, но вместо этого возвращает int A::*? Оператор области действия имеет приоритет перед оператором &, поэтому сначала следует запустить A::x, возвращая значение int lvalue, прежде чем адрес будет удален. то есть это должно быть точно так же, как &(A::x)? (Кстати, добавление скобок действительно работает).
  4. Немного отличается, конечно, оператор области, ссылающийся на элемент класса, но без объекта, к которому относится.

Так почему же именно A::x не возвращает адрес объекта x, но вместо этого возвращает адрес элемента, игнорируя приоритет :: перед тем &?

ответ

3

В стандарте C++ явно не указано приоритет оператора; можно недвусмысленно выводить приоритет оператора из правил грамматики, но этот подход не может оценить случайный частный случай, подобный этому, который не вписывается в традиционную модель приоритета оператора.

[expr.unary.op]/3:

В результате одноместной & оператора представляет собой указатель на его операнда. Операнд должен быть lvalue или квалифицированный идентификатор. Если операнд является квалифицирован-идентификатор именования нестатический или вариант члена m некоторого класса C с типом T, результат имеет тип «указатель на член класса C типа T» и является prvalue назначение C::m , В противном случае, если тип выражения равен T, результат имеет тип 'pointer to T' и является prvalue, который является адресом назначенного объекта или указателем на назначенную функцию.

/4:

Указатель на член только формируется, когда явное & используется и ее операндов является квалифицирован-идентификатор не заключен в скобки. [Примечание: , то есть выражение &(qualified-id), где квалифицированный идентификатор заключен в круглые скобки, не образует выражение типа «указатель на элемент».

[expr.prim.general]/9:

вложенное-имя-спецификатор, что обозначает класс, необязательно с последующим ключевым словом template, а затем, за которой следует название членом этого класса или одного из его базовых классов, является квалифицированный идентификатор.

Что все это добавляет к тому, что выражение вида &A::x имеет тип «указатель на член x класса A», если x не является статическим членом не всесоюзного класса A, и оператор приоритет на это не влияет.

8

В принципе, это означает, что синтаксис &A::x (без изменений) был выбран для обозначения указателя на элемент.

Если вы пишете, например, &(A::x), вы получите простой указатель, которого вы ожидаете.

Дополнительную информацию о указателях к членам, включая примечание об этом же свойстве, можно найти: here.

+0

Я думаю, что если бы это сработало иначе, это привело бы к большей путанице. Такая же последовательность идентификаторов и операторов, ссылающаяся на те же самые типы и элементы, что означает две разные вещи в зависимости от области действия: звучит как неприятность для меня. –

+0

@JohnSensebe определенно. Я изначально писал «quirk», но на самом деле это очень разумный выбор, хотя он может показаться странным вначале. – Quentin

 Смежные вопросы

  • Нет связанных вопросов^_^