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

Почему в параметрах С++ последнее значение должно быть добавлено последними?

Зачем добавлять параметры по умолчанию в С++?

4b9b3361

Ответ 1

Чтобы упростить определение языка и сохранить читаемый код.

void foo(int x = 2, int y);

Чтобы вызвать это и использовать значение по умолчанию, вам понадобится синтаксис:

foo(, 3);

Скорее всего, это было слишком странно. Другой альтернативой является указание имен в списке аргументов:

foo(y : 3);

Новый символ должен использоваться, потому что это уже означает что-то:

foo(y = 3); // assign 3 to y and then pass y to foo.

Метод именования был рассмотрен и отклонен комитетом ИСО, поскольку им было неудобно вводить новое значение в имена параметров за пределами определения функции.

Если вы заинтересованы в других основах проектирования С++, прочитайте The Design and Evolution of С++ от Stroustrup.

Ответ 2

Если вы определяете следующую функцию:

void foo( int a, int b = 0, int c );

Как вы могли бы вызвать функцию и поставить значение для a и c, но оставить b по умолчанию?

foo( 10, ??, 5 );

В отличие от некоторых других языков (например, Python), аргументы функции в C/С++ не могут быть указаны по имени, например:

foo( a = 10, c = 5 );

Если это было возможно, аргументы по умолчанию могут быть в любом месте списка.

Ответ 3

Представьте, что у вас была функция с этим прототипом:

void testFunction(bool a = false, bool b = true, bool c);

Теперь предположим, что я вызвал такую ​​функцию:

testFunction(true, false);

Как компилятор должен определить, какие параметры я имел в виду, чтобы указать значения для?

Ответ 4

Как видно из большинства ответов, наличие параметров по умолчанию, потенциально в любом месте списка параметров, увеличивает сложность и неоднозначность вызовов функций (как для компилятора, так и, что более важно, для пользователей этой функции).

Одна хорошая вещь о С++ заключается в том, что часто есть способ делать то, что вы хотите (даже если это не всегда хорошая идея). Если вы хотите иметь аргументы по умолчанию для разных позиций параметров, вы почти наверняка можете это сделать, написав перегрузки, которые просто обернутся и вызовут полностью параметризованную функцию inline:

 int foo( int x, int y);
 int foo( int y) {
     return foo( 0, y);
 }

И там у вас есть эквивалент:

 int foo( int x = 0, int y);

Ответ 5

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

(Это применяется к __cdecl, который, как правило, является значением по умолчанию для объявлений VС++ и __stdcall).

Ответ 6

Потому что он использует относительное положение аргументов, чтобы найти, какие параметры они соответствуют.

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

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

Ответ 7

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

Ответ 8

Это вопрос о соглашении о вызовах. Конвенция о вызове: Когда вы вызываете функцию, параметры вставляются в стек справа налево. например.

fun(int a, int b, int c);

стек выглядит следующим образом:                                            б                      с поэтому, если вы установите значение по умолчанию слева направо, как это:

fun(int a = 1, int b = 2, int c);

и вызывайте так:

fun(4,5);

ваш вызов означает набор a = 4, b = 5 и c = no значение;//что неправильно!

если вы объявите функцию следующим образом:

fun(int a, int b = 2, int c = 3);

и вызывайте так: fun(4, 5);

ваш вызов означает установить a = 4, b = 5 и c = значение по умолчанию (3);//что правильно!

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

Ответ 9

Цзин Цзэн прав. Я хотел бы добавить свои замечания здесь. Когда вызывается функция, аргументы вставляются в стек справа налево. Например, предположим, что у вас есть эта произвольная функция.

int add(int a, int b) {
  int c;
  c = a + b;
  return c;
}

Вот кадр стека для функции:

------
  b
------
  a
------
 ret
------
  c
------

Эта диаграмма выше представляет собой стек стека для этой функции! Как вы можете видеть, сначала b вставляется в стек, а затем вставляется в стек. После этого адрес возврата функции помещается в стек. Адрес возврата функции содержит местоположение в main(), из которого первоначально была вызвана функция, и после выполнения функции выполнение программы переходит к адресу возврата функции. Затем любые локальные переменные, такие как c, помещаются в стек.

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

Вероятно, более эффективным было то, что компилятор сначала быстро вставлял произвольные значения литерала по умолчанию в стек, поскольку они не хранятся в ячейке памяти и быстро наращивают стек. Подумайте о том, что было бы, если бы переменные были вначале вытолкнуты в стек, а затем в литералы. Доступ к ячейке памяти для процессора занимает относительно много времени по сравнению с вытягиванием буквального значения из схемы или регистров CPU. Поскольку для перетаскивания переменных в стек против литералов требуется больше времени, литералы должны будут ждать, тогда обратный адрес должен будет ждать, и локальные переменные также должны будут ждать. Вероятно, это не большая проблема эффективности, но только моя теория, почему аргументы по умолчанию всегда находятся в крайних правых положениях заголовка функции на С++. Это означает, что компилятор был разработан как таковой.