Подтвердить что ты не робот

Предоставлять аргументы по умолчанию для оператора индекса и оператора функции

В следующем коде я предоставил аргументы по умолчанию для оператора оператора массива .

struct st 
{
    int operator[](int x = 0)
    {
        // code here
    }
};

Но компилятор сгенерировал ошибку:

error: 'int st::operator[](int)' cannot have default arguments
     int operator[](int x = 0)

Но, если я предоставляю аргументы по умолчанию для оператора вызов функции.

struct st 
{
    int operator()(int x = 0)
    {
        // code here
    }
};

Он отлично работает.

Итак, у меня есть вопросы:

  • Почему не разрешены аргументы по умолчанию для оператора индекса массива?
  • Почему допустимые аргументы по умолчанию для оператора вызова функции?
4b9b3361

Ответ 1

Стандарт утверждает это довольно четко.

Аргументы по умолчанию не разрешены в перегрузка оператора оператор подписки.

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

и

operator[] должна быть нестатической функцией-членом только с одним параметром.

Пока для вызов функции вызова

operator() должна быть нестатической функцией-членом с произвольным числом параметров. Он может иметь аргументы по умолчанию.

Перегруженные операторы пытаются следовать одному и тому же поведению встроенных; со встроенным индексирующим оператором всегда требуется (только один) индекс, он не имеет аргументов по умолчанию. Тогда перегруженному оператору также не разрешается использовать аргументы по умолчанию. С другой стороны, функции всегда хороши для произвольного количества параметров и имеют аргументы по умолчанию.

Ответ 2

  • Почему не разрешен аргумент по умолчанию для оператора индекса массива?
  • Почему допустимый аргумент по умолчанию для оператора вызова функции?

В основном потому, что это говорит грамматика С++. Согласно A.4 [gram.expr]:

postfix-expression --> postfix-expression [ expr-or-braced-init-list ] 
                   --> postfix-expression ( expression-list opt ) 
                   --> simple-type-specifier (expression-list opt) 
                   --> typename-specifier ( expression-list opt )

Параметры для фигурных скобок необязательны, а для скобок нет. Как указано в комментарии, обратите внимание, что в скобках требуется взять ровно один параметр, тогда как фигурные скобки могут принимать произвольное количество параметров.

Также рассмотрите songyuanyao ответ для явного утверждения из стандарта.

Ответ 3

Я полагаю, вы действительно спрашиваете, почему стандарт позволяет один, а не другой. Причина заключается в основном в том, что люди ожидают, а не в некоторой технической логике, которая исключает дефолт в одном случае, но не в другом:

Это вопрос того, что люди ожидают от оператора []. Обычно это означает "Получить элемент в [...]", где мы используем int или какой-либо другой тип, чтобы сделать конкретный запрос о члене коллекции. Мы всегда интересуемся вопросом о конкретном члене, и у нас всегда есть конкретный вопрос.

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

Изменение этого, вероятно, заставит многих людей почесать головы, когда они увидят int x = vec[]

Ответ 4

Операторы (как перегрузка пользовательских типов, так и встроенных типов) предназначены для того, чтобы люди пользовались известными обозначениями из математики, логики и общего использования (хотя << и >> видели двойную службу как потоковое операторы и новаторские компромиссы должны были быть сделаны с учетом ограниченности символов, которые практически доступны на компьютерах). Чтобы обойти и разрешить вариации интуитивно понятных знакомых обозначений (например, подразумеваемых аргументов), кажется контрпродуктивным.

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