Ответ 1
В вопросе перечисляются три класса операторов. Думаю, объединение их в список помогает понять, почему несколько операторов ограничены тем, где они могут быть перегружены:
-
Операторы, которые должны быть перегружены как члены. Их довольно мало:
- Назначение
operator=()
. Разрешение присвоений, отличных от членов, похоже, открывает дверь для захвата операторами операторов, например, путем перегрузки для разных версий квалификацийconst
. Учитывая, что операторы присваивания являются довольно фундаментальными, что кажется нежелательным. - Вызов функции
operator()()
. Правила вызова функции и перегрузки достаточно сложны, как есть. Представляется, что не рекомендуется распространять правила дальше, разрешая операторам-операторам, не являющимся членами. - Подстрочный индекс
operator[]()
. Использование интересных типов индексов, похоже, может помешать доступу к операторам. Хотя существует небольшая опасность захвата перегрузок, похоже, нет большого выигрыша, но интересный потенциал для написания очень неочевидного кода. - Доступ к элементу класса
operator->()
. Вне рук я не вижу плохого злоупотребления перегрузкой этого оператора, не являющегося членом. С другой стороны, я тоже не вижу. Кроме того, оператор доступа к члену класса имеет довольно специальные правила, и игра с потенциальными перегрузками, мешающими им, кажется ненужным осложнением.
Хотя возможно перегрузка, каждый из этих членов является нечленом (особенно оператор нижнего индекса, который работает с массивами/указателями, и это может быть по обе стороны от вызова) кажется удивительным, если, например, назначение может быть захвачен не-членной перегрузкой, которая лучше соответствует одному из назначений членов. Эти операторы также довольно асимметричны: вы, как правило, не хотели бы поддерживать преобразование с обеих сторон выражения, включающего эти операторы.
Тем не менее, например, для библиотеки лямбда-выражения было бы хорошо, если бы можно было перегрузить все эти операторы, и я не думаю, что существует некоторая техническая причина для предотвращения перегрузки этих операторов.
- Назначение
-
Операторы, которые должны быть перегружены как функции, не являющиеся членами.
- Пользовательский литерал
operator"" name()
Этот оператор несколько нечетный и, возможно, не действительно оператор. В любом случае нет объекта для вызова этого члена, для которого могут быть определены члены: левый аргумент определяемых пользователем литералов всегда является встроенным.
- Пользовательский литерал
-
Не упоминается в вопросе, но есть и оператор, который не может быть перегружен вообще:
- Селектор элементов
.
- Оператор доступа к объекту с указателем на элемент
.*
- Оператор области
::
- Тернарный оператор
?:
Эти четыре оператора считались слишком фундаментальными, чтобы вообще вмешиваться. Хотя есть предложение разрешить перегрузку
operator.()
, в какой-то момент нет сильной поддержки, которая делает это (основным вариантом использования будет интеллектуальная ссылка). Хотя, безусловно, есть некоторые контексты, которые можно себе представить, где было бы хорошо перегрузить эти операторы. - Селектор элементов
-
Операторы, которые могут быть перегружены либо как члены, либо как нечлены. Это основная часть операторов:
- Пред-и пост-инкремент/-ограничение
operator++()
,operator--()
,operator++(int)
,operator--(int)
- [унарное] разыменование
operator*()
- [унарный] адрес
operator&()
- [унарные] знаки
operator+()
,operator-()
- Логическое отрицание
operator!()
(илиoperator not()
) - Побитовая инверсия
operator~()
(илиoperator compl()
) - Сравнение
operator==()
,operator!=()
,operator<()
,operator>()
,operator<=()
иoperator>()
- [двоичная] арифметика
operator+()
,operator-()
,operator*()
,operator/()
,operator%()
- [бинарный] побитовый
operator&()
(илиoperator bitand()
),operator|()
(илиoperator bit_or()
),operator^()
(илиoperator xor()
) - Побитовый сдвиг
operator<<()
иoperator>>()
- Логика
operator||()
(илиoperator or()
) иoperator&&()
(илиoperator and()
) - Операция/назначение
[email protected]=()
(для@
является подходящим символом оператора() - Последовательность
operator,()
(для которой перегрузка фактически убивает свойство последовательности!) - Указатель указателя на элемент
operator->*()
- Управление памятью
operator new()
,operator new[]()
,operator new[]()
иoperator delete[]()
Операторы, которые могут быть перегружены либо как члены, либо как нечлены, не являются необходимыми для обслуживания основных объектов, как и другие операторы. Это не значит, что они не важны. Фактически, этот список содержит несколько операторов, где довольно сомнительно, должны ли они быть перегружаемыми (например, адрес
operator&()
или операторы, которые обычно вызывают последовательность, т.е.operator,()
,operator||()
иoperator&&()
. - Пред-и пост-инкремент/-ограничение
Конечно, стандарт С++ не дает оснований для объяснения того, почему все делается так, как это делается (а также нет записей о ранних днях, когда эти решения принимаются). Лучшее обоснование, вероятно, можно найти в "Design and Evolution of С++" Бьярне Страуструпа. Я помню, что операторы обсуждались там, но, похоже, нет доступной электронной версии.
В целом я не думаю, что существуют серьезные причины для ограничений, отличных от потенциальных осложнений, которые в основном не считаются заслуживающими внимания. Однако я бы сомневался, что ограничения, вероятно, будут отменены, поскольку взаимодействие с существующим программным обеспечением неизбежно изменит смысл какой-либо программы непредсказуемыми способами.