Что делает оператор унарного плюса?

Что делает унарный оператор плюс? Есть несколько определений, которые я нашел (здесь и здесь), но я до сих пор не знаю, для чего он будет использоваться. Кажется, это ничего не делает, но для этого есть причина, верно?

Ответ 1

Это должно быть перегружено, если вы чувствуете необходимость; для всех предопределенных типов это по существу не-op.

Практическое использование нетапового унарного арифметического оператора довольно ограничено и, как правило, связано с последствиями использования значения в арифметическом выражении, а не с самим оператором. Например, его можно использовать для принудительного расширения от меньших интегральных типов до int или обеспечения того, чтобы результат выражения обрабатывался как rvalue и поэтому не был совместим с опорным параметром не const. Однако я утверждаю, что эти виды использования лучше подходят для кодового гольфа, чем для читаемости.: -)

Ответ 2

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

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

void foo(unsigned short x)
{
 std::cout << "x is an unsigned short" << std::endl;
}

void foo(int x)
{
 std::cout << "x is an int" << std::endl;
}

int main()
{
 unsigned short x = 5;
 foo(+x);
}

Отобразится "x is int".

Итак, в этом примере унарный плюс создал новое значение с другим типом и подписью.

Ответ 3

Из второго издания K & R:

Унарный + новый с стандартом ANSI. Он был добавлен для симметрии с унарным -.

Ответ 4

Я видел, что он используется для ясности, чтобы подчеркнуть положительное значение, отличное от отрицательного значения:

shift(+1);
shift(-1);

Но это довольно слабое использование. Ответ определенно перегружен.

Ответ 5

Одна вещь, которую встроенный унарный + делает, превращает lvalue в rvalue. Например, вы можете сделать это

int x;
&x;

но вы не можете этого сделать

&+x;

:)

P.S. "Перегрузка" определенно не является правильным ответом. Унарный + был унаследован от C и не существует перегрузки оператора на уровне пользователя в C.

Ответ 6

Главное, что делает унарный +, - это продвижение типа к int для типов данных меньшего размера. Это может быть весьма полезно, если вы пытаетесь распечатать данные char, используя std::cout как числовые данные.

char x = 5;
std::cout << +x << "\n";

сильно отличается от

char x=5;
std::cout << x << "\n";

Он также доступен для перегрузки, но на практике ваша перегрузка должна быть почти NOP.

Ответ 7

Если вам понадобится напечатать числовое значение необработанных байтов (например, небольшие числа, сохраненные как char) для отладки или любой другой причины, унарный + может упростить код печати. Рассмотрим

char c = 42;
cout << c << endl;           // prints "*\n", not what you want in this case
cout << (int)c << endl;      // prints "42\n", ok
cout << +c << endl;          // prints "42\n", much easier to type

Это просто быстрый пример. Я уверен, что есть другие случаи, когда унарный + может обрабатывать ваши байты больше как числа, а не как текст.

Ответ 8

Исторический лакомый кусочек. Комитет по стандартизации C99 также считал, что существующее использование унарного плюса было довольно редким, о чем свидетельствует их повторное использование для достижения еще одной функции на языке: торможение оценки времени с плавающей точкой с постоянными выражениями. См. Следующую цитату из C Обоснование, раздел F.7.4:

Ранняя версия этой спецификации допускала постоянную арифметику времени перевода, но уполномочил унарный + оператор, применяемый к операнду, блокировать время перевода оценка постоянных выражений.

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

Ответ 9

Не много. Общий аргумент для разрешения перегрузки operator+() заключается в том, что для перегрузки operator-() существует определенно реальное использование мира, и было бы очень странно (или асимметрично), если бы вы допустили перегрузку operator-(), но не operator+().

Я считаю, что сначала прочитал этот аргумент от Stroustrop, но у меня нет моих книг со мной, чтобы проверить это. Возможно, я ошибаюсь.

Ответ 10

Унарный плюс присутствовал в C, где он ничего не делал (как и ключевое слово auto). Чтобы этого не было, Страуструпу пришлось бы ввести безвозмездную несовместимость с C.

Как только это было на С++, было естественно разрешить функцию перегрузки, как унарный минус, и Stroustrup мог бы ввести ее по этой причине, если она еще не была там.

Итак, это ничего не значит. Его можно использовать как своеобразное украшение, чтобы сделать вещи более симметричными, используя, например, +1.5, как противоположность -1,5. В С++ он может быть перегружен, но это будет путать, если operator+() что-то делает. Помните стандартное правило: при перегрузке арифметических операторов делайте такие вещи, как int do.

Если вы ищете причину, почему она там, найдите что-то о ранней истории C. Я подозреваю, что нет веской причины, поскольку C не был действительно разработан. Рассмотрим бесполезное ключевое слово auto (по-видимому, в отличие от static, которое теперь перерабатывается в С++ 0x) и ключевое слово entry, которое никогда ничего не делало (и позже опущено на C90). Там известное письмо, в котором Ритчи или Керниган говорят, что, когда они поняли, что у оператора есть проблемы, были уже три установки с тысячами строк кода, которые они не хотели нарушать.

Ответ 11

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

  • Продвижение: new_type operator+(old_type)
  • Конверсия: new_type(old_type)
  • В ролях: operator(new_type)(old_type)
  • Принуждение: new_type operator=(old_type)

Конечно, из моей интерпретации заметки в одном из пособий по Microsoft/С++, которые я прочитал около 15 лет назад, так что возьмите его с солью.

Ответ 12

#include <stdio.h>
int main()
{
    unsigned short x = 5;
    printf ("%d\n",sizeof(+x)); 
    printf ("%d\n",sizeof(x)); 
    return 0;
}

Как показано в примере выше, унарный + действительно изменяет тип, размер 4 и 2 соответственно. Странно, что выражение + x действительно вычисляется в sizeof, я думал, что этого не должно было быть. Возможно, это связано с тем, что sizeof имеет тот же приоритет, что и унарный +.

Ответ 13

Я полагаю, вы могли бы использовать его, чтобы всегда делать число положительным. Просто перегрузите оператор унарного +, чтобы он был абс. Не стоит смешивать своих коллег-разработчиков, если только вы просто не хотите запутать свой код. Тогда это будет хорошо работать.

Ответ 14

EDIT Переписал полностью, потому что я был waaaayyy в своем первоначальном ответе.

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

public struct Acceleration
{
    private readonly decimal rate;
    private readonly Vector vector;

    public Acceleration(decimal rate, Vector vector)
    {
        this.vector = vector;
        this.rate = rate;
    }

    public static Acceleration operator +(Acceleration other)
    {
        if (other.Vector.Z >= 0)
        {
            return other;
        }
        return new Acceleration(other.Rate, new Vector(other.vector.X, other.Vector.Y, -other.vector.Z));
    }

    public static Acceleration operator -(Acceleration other)
    {
        if (other.Vector.Z <= 0)
        {
            return other;
        }
        return new Acceleration(other.Rate, new Vector(other.vector.X, other.Vector.Y, -other.vector.Z));
    }

    public decimal Rate
    {
        get { return rate; }
    }

    public Vector Vector
    {
        get { return vector; }
    }
}