C ++ возвращаемый тип операторов +, - и * на интегральных типах [duplicate]

TL; DR: Попробуйте использовать Html.Partial вместо Renderpage


Я получал Object reference not set to an instance of an object, когда пытался сделать вид в представлении, отправив ему модель, например это:

@{
    MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null

Отладка показала, что модель была Null внутри MyOtherView. Пока я не сменил его на:

@{
    MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);

И это сработало.

Кроме того, причина, по которой я не имел Html.Partial для начала, заключалась в том, что Visual Studio иногда выдает ошибки, (f9), если он находится внутри другого построенного цикла foreach, хотя это не ошибка:

@inherits System.Web.Mvc.WebViewPage
@{
    ViewBag.Title = "Entity Index";
    List<MyEntity> MyEntities = new List<MyEntity>();
    MyEntities.Add(new MyEntity());
    MyEntities.Add(new MyEntity());
    MyEntities.Add(new MyEntity());
}
<div>
    @{
        foreach(var M in MyEntities)
        {
            // Squiggly lines below. Hovering says: cannot convert method group 'partial' to non-delegate type Object, did you intend to envoke the Method?
            @Html.Partial("MyOtherView.cshtml");
        }
    }
</div>

Но я смог запустить приложение без проблем с этим " ошибка". Я смог избавиться от ошибки, изменив структуру цикла foreach, чтобы выглядеть так:

@foreach(var M in MyEntities){
    ...
}

Хотя я чувствую, что это потому, что Visual Studio неправильно интерпретировала амперсанды и скобки .

15
задан sth 10 October 2011 в 11:05
поделиться

3 ответа

Взято из стандарта C ++:

4.5 Интегральные рекламные акции [conv.prom] 1 Rvalue типа char, signed char, unsigned char, short int или unsigned short int может быть преобразовано на rvalue типа int, если int может представлять все значения типа источника; в противном случае исходное значение rvalue может быть преобразовано в rvalue типа unsigned int.

На практике это означает, что все операции (по типам в списке) фактически оцениваются по типу int, если он может покрыть все значение, с которым вы имеете дело, иначе оно выполняется на unsigned int. В первом случае значения сравниваются как unsigned int, потому что один из них был unsigned int, и поэтому -1 является «большим», чем 2. Во втором случае значения a, сравниваемые как целые числа со знаком, как int, вся область как short, так и unsigned short и т. д. меньше 2.

(История вопроса: на самом деле все это сложное определение о покрытии всех случаев таким образом приводит к тому, что компиляторы могут фактически игнорировать фактический тип (!) :) и просто заботиться о размере данных.)

1
ответ дан Daniel Fischer 25 August 2018 в 18:20
поделиться

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

Целочисленные акции: если int может представлять все значения типа, то операнд продвигается до int. Это относится как к short, так и к unsigned short на большинстве платформ. Преобразование, выполняемое на этом этапе, выполняется на каждом операнде индивидуально, независимо от другого операнда. (Есть больше правил, но это тот, который применяется.)

Обычные арифметические преобразования: если вы сравниваете unsigned int с signed int, так как ни один из них не включает весь диапазон другого, и оба имеют одинаковый ранг, то оба они преобразуются в тип unsigned. Это преобразование выполняется после изучения типа обоих операндов.

Очевидно, что «обычные арифметические преобразования» не всегда применяются, если не существует двух операндов. Вот почему существуют два набора правил. Например, один из них - это то, что операторы сдвига << и >> не выполняют обычных арифметических преобразований, поскольку тип результата должен зависеть только от левого операнда (поэтому, если вы видите кого-то типа x << 5U, тогда U означает «ненужное»).

Разбивка: предположим, что типичная система с 32-битным int и 16-битным коротким.

int a = -1;         // "signed" is implied
unsigned b = 2;     // "int" is implied
if (a < b)
    puts("a < b");  // not printed
else
    puts("a >= b"); // printed
  1. Сначала поддерживаются два операнда. Поскольку оба являются int или unsigned int, промо-акции не выполняются.
  2. Затем два операнда преобразуются в один и тот же тип. Поскольку int не может представлять все возможные значения unsigned, а unsigned не может представлять все возможные значения int, нет очевидного выбора. В этом случае оба преобразователя преобразуются в unsigned.
  3. При преобразовании из подписанного в unsigned 232 повторно добавляется к значению с подписью до тех пор, пока оно не окажется в диапазоне значения без знака.
  4. Таким образом, сравнение становится if (4294967295u < 2u), что является ложным.

Теперь попробуем это с помощью short:

short c = -1;          // "signed" is implied
unsigned short d = 2;
if (c < d)
    puts("c < d");     // printed
else
    puts("c >= d");    // not printed
  1. Во-первых, продвигаются два операнда. Поскольку оба они могут быть точно представлены int, они продвигаются до int.
  2. Затем они преобразуются в один и тот же тип. Но они уже одного типа, int, поэтому ничего не сделано.
  3. Таким образом, сравнение становится if (-1 < 2), что верно.

Написание хорошего кода : Есть простой способ поймать эти «gotchas» в вашем коде. Просто всегда компиляция с включенными предупреждениями и исправление предупреждений. Я предпочитаю писать такой код:

int x = ...;
unsigned y = ...;
if (x < 0 || (unsigned) x < y)
    ...;

Вы должны следить за тем, чтобы любой код, который вы пишете, не запускался в другой подписанный vs. unsigned gotcha: signed overflow. Например, следующий код:

int x = ..., y = ...;
if (x + 100 < y + 100)
    ...;
unsigned a = ..., b = ...;
if (a + 100 < b + 100)
    ...;

Некоторые популярные компиляторы оптимизируют (x + 100 < y + 100) до (x < y), но это история за другой день.

Сноска: обратите внимание, что если для int подразумевается signed, short, long и long long, это НЕ подразумевается для char. Вместо этого это зависит от платформы.

20
ответ дан Dietrich Epp 25 August 2018 в 18:20
поделиться

Процесс преобразования для C ++ описывается как обычные арифметические преобразования . Тем не менее, я думаю, что наиболее релевантное правило находится в разделе подкатегории conv.prom: Интегральные рекламные акции 4.6.1 :

Значение целочисленного типа, отличного от bool, char16_t, char32_t или wchar_t, чей целочисленный ранг преобразования ([conv.rank]) меньше ранга int, может быть преобразован в prvalue типа int, если int может представлять все значения типа источника; в противном случае исходное значение prvalue может быть преобразовано в prvalue типа unsigned int.

Самое смешное, что есть слово «can», которое, я думаю, предполагает, что эта акция выполняется по усмотрению компилятора.

Я также нашел этот фрагмент C-spec, который намекает на отсутствие продвижения:

11   EXAMPLE 2       In executing the fragment
              char c1, c2;
              /* ... */
              c1 = c1 + c2;
     the ``integer promotions'' require that the abstract machine promote the value of each variable to int size
     and then add the two ints and truncate the sum. Provided the addition of two chars can be done without
     overflow, or with overflow wrapping silently to produce the correct result, the actual execution need only
     produce the same result, possibly omitting the promotions.

Существует также определение «ранга» . Список правил довольно длинный, но поскольку он применим к этому вопросу, «ранг» прост:

Ранг любого беззнакового целочисленного типа должен быть равен ранга соответствующего знакового целочисленного типа.

0
ответ дан nobar 25 August 2018 в 18:20
поделиться
Другие вопросы по тегам:

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