Почему ссылки запрещены в std :: варианте?

Согласно вашему коду:

String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<=name.length; i++) {
  System.out.print(name[i] +'\n');
}

Если вы проверите System.out.print (name.length),

, вы получите 3;

, что означает, что длина вашего имени равна 3

, ваш цикл работает от 0 до 3, который должен работать либо от «0 до 2», либо от «1 до 3»

Ответ

String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<name.length; i++) {
  System.out.print(name[i] +'\n');
}
13
задан Cinder Biscuits 16 January 2019 в 13:57
поделиться

1 ответ

По сути, причина, по которой optional и variant не допускают ссылочные типы, заключается в том, что существует разногласие относительно того, что присваивание (и, в меньшей степени, сравнение) должно делать для таких случаев. optional проще, чем variant показать в примерах, поэтому я буду придерживаться этого:

int i = 4, j = 5;
std::optional<int&> o = i;
o = j; // (*)

Отмеченную линию можно интерпретировать как:

  1. Rebind o, такой, что &*o == &j. В результате этой линии сами значения i и j остаются неизменными.
  2. Назначьте через o, такое &*o == &i все еще верно, но теперь i == 5.
  3. Полностью запретить назначение.

Assign-through - это поведение, которое вы получаете, просто нажимая = до = [1117], rebind - более надежная реализация и именно то, что вам действительно нужно (см. Также this вопрос , а также доклад Мэтта Калабрезе о ссылочных типах ).

Другой способ объяснить разницу между (1) и (2) заключается в том, как мы могли бы реализовать обе эти возможности извне:

// rebind
o.emplace(j);

// assign through
if (o) {
    *o = j;
} else {
    o.emplace(j);
}

Документация Boost.Optional предоставляет это обоснование:

Семантика перепривязки для назначения инициализированных необязательных ссылок была выбрана для обеспечения согласованности среди состояний инициализации даже за счет отсутствия согласованности с семантикой голых ссылок C ++. Это правда, что optional<U> стремится вести себя как можно лучше, чем U, когда он инициализируется; но в случае, когда U равно T&, это приведет к несовместимому поведению по отношению к состоянию инициализации lvalue.

Представьте optional<T&> переадресацию присваивания ссылочному объекту (таким образом, изменяя значение ссылочного объекта, но не привязывая), и рассмотрите следующий код:

optional<int&> a = get();
int x = 1 ;
int& rx = x ;
optional<int&> b(rx);
a = b ;

Что делает присваивание?

[ 1151] Если a не неинициализирован , ответ ясен: он связывается с x (теперь у нас есть еще одна ссылка на x). Но что, если a уже инициализирован ? это изменило бы значение ссылочного объекта (что бы это ни было); что не согласуется с другим возможным случаем.

Если бы optional<T&> присваивал так же, как T&, вы никогда бы не смогли использовать присваивание Optional без явной обработки предыдущего состояния инициализации, если ваш код не способен функционировать, будь то после присваивания, a алиасирует то же самое объект как b или нет.

То есть вам нужно было бы различать, чтобы быть последовательным.

Если в вашем коде привязка к другому объекту невозможна, то весьма вероятно, что привязка в первый раз также не подходит. В таком случае присвоение неинициализированному optional<T&> должно быть запрещено. Вполне возможно, что в таком сценарии является предварительным условием, что значение lvalue должно быть уже инициализировано. Если это не так, тогда связывание в первый раз в порядке, а повторное связывание - нет, что очень маловероятно. В таком сценарии вы можете назначить само значение непосредственно, например:

assert(!!opt);
*opt=value;

Отсутствие соглашения о том, что должна делать эта строка, означало, что было проще просто полностью запретить ссылки , так что большая часть значений optional и variant может, по крайней мере, сделать это для C ++ 17 и начать быть полезной. Ссылки всегда могут быть добавлены позже - или так аргумент пошел. [Тысяча сто пятьдесят-пять]

0
ответ дан Barry 16 January 2019 в 13:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: