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

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

16 ответов

Решение

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

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

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

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

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);
}

Это покажет "х является int".

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

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

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

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

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

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

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

int x;
&x;

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

&+x;

:)

PS "Перегрузка", безусловно, не правильный ответ. Одинарный + был унаследован от C и в C. нет перегрузки операторов уровня пользователя

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Конечно, это из моей интерпретации заметки в одном из (действительно старых) руководств по c/ C++ от Microsoft, которые я прочитал около 15 лет назад, так что возьмите его с толку соли.

#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 имеет тот же приоритет, что и унарный +.

Еще одно интересное использование C++, о котором я здесь не упоминал, заключается в том, что оно позволяет преобразовывать лямбда-выражения без захвата в указатели на функции:

      void (*func_ptr)();
func_ptr = +[](){};

int (*func_ptr2)(int, int);
func_ptr2 = +[](int x, int y){return x + y;};

The Оператор принудительно преобразует незахватывающую лямбду в указатель на функцию с помощью неявной объявленной пользователем функции преобразования.

РЕДАКТИРОВАТЬ Переписано полностью, потому что я был не в своем оригинальном ответе.

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

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; }
    }
}

Просто это используется, чтобы убедить, какие числа положительны

например;

int a=10;
System.out.println(+x);// prints 10(that means,that number 10 multiply by +1,{10*+1})

//if we use unary minus

int a=10;
System.out.println(-x);//prints -10(that means,that number 10 multiply by +1,{10*-1})

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

Другие вопросы по тегам