Не был бы он иметь смысл если p->m
был просто синтаксический сахар для (*p).m
? По существу, каждый operator->
то, что я когда-либо писал, возможно, было реализовано следующим образом:
Foo::Foo* operator->()
{
return &**this;
}
Есть ли любой случай, где я хотел бы p->m
означать что-то еще, чем (*p).m
?
оператор -> ()
имеет странное отличие неявно вызывается несколько раз , в то время как тип возврата позволяет . Самый ясный способ показать это - с помощью кода:
struct X {
int foo;
};
struct Y {
X x;
X* operator->() { return &x; }
};
struct Z {
Y y;
Y& operator->() { return y; }
};
Z z;
z->foo = 42; // Works! Calls both!
Я вспоминаю случай, когда такое поведение было необходимо, чтобы позволить объекту вести себя как прокси для другого объекта в контексте, подобном умному указателю, хотя я не могу вспомнить Детали. Что я действительно помню, так это то, что я мог добиться того, чтобы поведение работало так, как я предполагал, используя синтаксис a-> b
, используя этот странный особый случай; Я не смог найти способ заставить (* a) .b
работать аналогичным образом.
Не уверен, что это отвечает на ваш вопрос; на самом деле я говорю: «Хороший вопрос, но он еще более странный!»
Одним из вариантов использования может быть создание DSL внутри C ++ в соответствии со строками Boost Karma (хотя, похоже, это не приводит к перегрузке ->
в их библиотеке), где вы полностью меняете смысл традиционных операторов C ++. Вопрос о том, хорошая ли это идея, определенно остается предметом обсуждения.
Я думаю, что он используется для shared_ptr <> при повышении (например). Это делает их "похожими" на обычные указатели, хотя они и являются специальными указателями (подсчет ссылок afaik).
Обычные указатели предлагают p->m
и (*p).m
, причем p->m
является более распространенным. Если бы вы разрешили перегрузку только одного из них, то это было бы несовместимо с типом по умолчанию. Что касается того, почему бы не позволить компилятору переписать его, простой ответ заключается в том, что иногда вы не хотите, чтобы operator-> возвращал T*, в то время как operator* возвращает T&. Разрешение перегружать их по отдельности позволяет создавать комбинации, о которых вы не всегда можете подумать. Но было бы глупо запрещать это только потому, что в настоящее время мы не можем придумать никаких причин, чтобы изменить это. Например, вы можете иметь класс int128 и перегрузить operator+=, чтобы он означал экспоненциацию вместо этого, если вам так хочется.
Вы можете захотеть выполнить некоторые другие операции, например, инкрементирование переменной (подсчет доступа) или даже некоторые проверки безопасности и т.д. С другой стороны, у меня никогда не было необходимости перегружать оператор-> ...