Проблемы с поиском имен членов класса C ++ (в отношении формулировки стандарта n3225) - PullRequest
2 голосов
/ 20 января 2011

Я очень озадачен стандартом 10.2 / 13,

[Примечание. Даже если результат поиска по имени однозначен, использование имени, найденного в нескольких подобъектах, может быть неоднозначным (4.11, 5.2.5, 5.3.1, 11.2) .— примечание] [Пример:

struct B1 {
  void f();
  static void f(int);
  int i;
};
struct B2 {
  void f(double);
};
struct I1: B1 { };
struct I2: B1 { };
struct D: I1, I2, B2 {
  using B1::f;
  using B2::f;
  void g() {
    f(); // Ambiguous conversion of this
    f(0); // Unambiguous (static)
    f(0.0); // Unambiguous (only one B2)
    int B1::* mpB1 = &D::i; // Unambiguous
    int D::* mpD = &D::i; // Ambiguous conversion
  }
};

Я не могу понять, почему это однозначно int B1 :: * mpB1 = & D :: i;// Однозначный

Visual C ++, Gcc и CLang все говорят, что это неоднозначный доступ к D :: i!

Формулировка, похоже, связана с основной проблемой # 39 http://www.open -std.org / jtc1 / sc22 / wg21 / docs / cwg_defects.html # 39 , и окончательное предложение находится здесь: http://www.open -std.org / jtc1 / sc22 / wg21 / docs /paper / 2004 / n1626.pdf

Теперь я обнаружил, что новые формулировки на основе алгоритмов (10.2 / 3-10.2 / 6) еще более запутаны, поскольку ни одна из заметок в 10.2 / 9, 10.2/ 10, 10.2 / 11 и 10.2 / 13 полностью соответствует 10.2 / 3-10.2 / 6.Я могу принять 10.2 / 9-10.2 / 11 в качестве исключения, но я особенно запутался в 10.2 / 13.Я понятия не имею о намерениях 10.2 / 13.

. Как следует искать пример в 10.2 / 13 в соответствии с 10.2 / 3-10.2 / 6?Каково намерение 10.2 / 13, т. Е. В какой ситуации 10.2 / 13 рассматривается как исключение из 10.2 / 3-10.2 / 6?

Пожалуйста, дайте мне несколько советов.Большое спасибо.


Подумав, я думаю, что намерение 10.2 / 13 для меня яснее.

int B1 :: * mpB1 = & D :: i;// Однозначный

Это должно быть однозначным, и текущие компиляторы ошибаются в этом.Это недвусмысленно, потому что указатель на инициализацию членов класса пока не требует доступа к объекту.

int D :: * mpD = & D :: i;// Неоднозначное преобразование

Это фактически означает, что при преобразовании из int B1 :: * mpB1 в int D :: * mpD преобразование является неоднозначным из-за неоднозначных базовых классов.

Ответы [ 4 ]

4 голосов
/ 20 января 2011

Для случая B1 :: * интерпретация однозначна, просто является смещением от начала B1 до i.

В 5.3.1 / 3:

struct A { int i; };
struct B : A { };
... &B::i ... // has type int A::*

Таким образом, хитрость заключается в том, чтобы & D :: i имел тип B1 :: * в первую очередь. Тогда:

int B1::* mpB1 = &D::i; // Unambiguous

просто. Интерес проявляется тогда:

int D::* mpD = &D::i; // Ambiguous conversion

Здесь RHS относится к типу B1 :: * и нуждается в преобразовании, поскольку нам нужно определить, на какую базу ссылаются.

2 голосов
/ 20 января 2011

Это:

int B1::* mpB1 = &D::i; // Unambiguous

Однозначно, поскольку результат присваивается pointer to member класса B.
Так что не имеет значения, какой i выбран в качествеотносительно члена B (не родительского класса D).

Так что это однозначно для нас с вами, но я не думаю, что компилятор может с этим справиться.

0 голосов
/ 21 января 2011

FWIW, я копирую свой ответ, который я передал в usenet копию этого вопроса:

Привет всем,

Я очень запутался в стандарте n3225 10.2 / 13,
[Примечание: даже если результат поиска имени однозначен, использование имя, найденное в нескольких подобъектах, все еще может быть неоднозначным (4.11, 5.2.5, 5.3.1, 11.2). - примечание] [Пример:

struct B1 {
  void f();
  static void f(int);
  int i;
};
struct B2 {
  void f(double);
};
struct I1: B1 { };
struct I2: B1 { };
struct D: I1, I2, B2 {
  using B1::f;
  using B2::f;
  void g() {
    f(); // Ambiguous conversion of this
    f(0); // Unambiguous (static)
    f(0.0); // Unambiguous (only one B2)
    int B1::* mpB1 = &D::i; // Unambiguous
    int D::* mpD = &D::i; // Ambiguous conversion
  }
};

Я не могу понять, почему это однозначно int B1 :: * mpB1 = & D :: i; // недвусмысленный

&D::i имеет тип int B1::* и однозначно относится к элементу данных i из B1. Если вы разыменовываете его с помощью D объекта или если вы присваиваете ему int D::*, вы получите двусмысленность при необходимости.

Visual C ++, Gcc и CLang говорят, что это неоднозначный доступ к D :: i!

Ни один из этих компиляторов пока не реализует 10.2.

Формулировка, похоже, связана с основной проблемой # 39 http://www.open -std.org / jtc1 / sc22 / wg21 / docs / cwg_defects.html # 39 и окончательное предложение здесь: http://www.open -std.org / ОТК1 / SC22 / wg21 / документы / документы / 2004 / n1626.pdf Теперь я обнаружил, что новые формулировки на основе алгоритма (10.2 / 3-10.2 / 6) еще более запутанным, потому что ни один из примечаний в 10.2 / 9, 10.2 / 10, 10.2 / 11 и 10.2 / 13 полностью соответствует 10.2 / 3-10.2 / 6. я могу взять 10.2 / 9-10.2 / 11 как исключения, но меня особенно смущает 10.2 / 13. Я понятия не имею о намерении 10.2 / 13.

Вам нужно привести примеры, которые показывают, чего вы не понимаете.

Как следует искать пример в 10.2 / 13 в соответствии с 10.2 / 3-10.2 / 6? Какова цель 10.2 / 13, то есть Ситуация, из которой 10.2 / 13 рассматривается как исключение 10.2 / 3-10.2 / 6?

Новые правила поиска, основанные на алгоритме, отделяют проблемы времени выполнения (поиск уникальный объект) с точки зрения времени компиляции / поиска (поиск объявления, которое имя относится к).

В новой редакции правильно сформулировано следующее:

struct Z { int z; };
struct X : Z { };
struct Y : Z { };
struct A : X, Y { };

struct B : A {
  using A::z;
};

Объявление using A::x; вводит имя члена в B, которое относится к декларация Z::z. В декларативном контексте это прекрасно. ошибка возникает только при доступе к B::z в качестве выражения доступа члена (5.2.5).

Не расстраивайтесь из-за того, что ошиблись в случае указателя на член. В прошлом я тоже это делал , и соответствующий отчет о проблеме фактически превратил его в черновик C ++ 0x. К счастью, изменили его обратно , когда заметили, что изменение было неправильным.

0 голосов
/ 20 января 2011

Быстрая проверка по разделу 10 ИСО МЭК 14882 2003 года не имеет этого примера или чего-либо подобного этому. C ++ 0x является черновым стандартом, а VC ++ / GCC / CLang ему не соответствуют.

Угадай: это побочный продукт новой auto печати, которого нет в старом стандарте C ++.

...