2016-09-27 5 views
3
struct A { 
    int i; 
}; 

struct B { 
    A a; 

    operator A*() { return &a; } 
}; 

int main(int argc, char *argv[]) 
{ 
    B b; 

    return b->i; 
} 

g++ сообщает error: base operand of ‘->’ has non-pointer type ‘B’Почему этот класс неявно конвертируется в указатель?

Почему? Я выяснил, как обойти эту проблему (используя operator->), но я не понимаю, почему неявное преобразование не происходит.

ответ

5

Это является следствием того, как разрешение перегрузки определяется для оператора ->. Цитируя C++ 14 [over.match.oper]/3:

Для оператора ,, унарный оператор & или оператора ->, встроенный в кандидаты набор пуст.

То есть, если левая сторона операнд -> имеет класс или тип перечисления, то -> никогда не будет иметь встроенный в значении; вместо этого, поиск имени для operator-> в качестве члена класса левого операнда должен преуспеть.

Если встроенный -> оператор был кандидатом, то компилятор может рассмотреть неявные преобразования, которые позволили бы B быть преобразованы к типу, что встроенный -> может принять, но это не является кандидатом, так что не происходит.

3

Поскольку C++ будет только неявно преобразовывать экземпляр класса, когда он знает, к чему он должен преобразоваться. Если вы используете такие выражения, как b->, он не может знать , что тип указателя (если таковые имеются) вы хотите, чтобы преобразовать его, и будет использовать только нормальные операторы (которые не определены, если не перегружена):

B b; 

// calls B::operator-> since that's what you tell it to do 
b->i; 

// calls B::operator A* since it knows it's implicitly converting to A* 
A *a = b; 

Если вы хотите использовать первое выражение здесь, то правильно путь к перегрузке operator->:

class B { 
    /* ... */ 

    A* operator ->() { return &a; } 
} 
3

но я не понимаю, почему неявное преобразование не происходит.

Для этого не существует контекста. operator-> применяется неявно к указателям или к типам классов с указанным оператором. Но все. Нет другой последовательности, через которую компилятор будет искать ее. В этом случае встроенный кандидат, установленный для b->, пуст, нет operator->, поэтому скомпилируйте ошибку.

Вы просто хотите добавить:

A* operator->() { return &a; }