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

86

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

vrish88
источник
3
Я думаю, что историческая причина сильно недооценена.
Wolf
3
Вопрос с тремя разными языковыми тегами довольно неоднозначный / плохой! Ответы сильно различаются для C # (перегружаемый) и C (без перегрузки) и C ++ (перегружаемый, но наследующий это от C и, следовательно, его свойства).
legends2k
Я хотел бы добавить ссылку на 10 основных недостатков C # Эрика Липперта. Вы найдете унарный оператор плюса в почетных упоминаниях: informit.com/articles/article.aspx?p=2425867 Он в основном говорит, что его следует удалить или никогда не следует добавлять.
Ноэль Видмер,

Ответы:

57

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

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

Джеффри Хантин
источник
7
На самом деле это не так, как показывают несколько примеров ниже.
jkerian
3
Хорошо, я куплю, что у него есть несколько применений, но большинство описанных ниже применений связаны с тем фактом, что это числовое выражение, построенное с использованием оператора no-op: например, повышение до значения intrvalue и его результат являются эффектами выражения -ness, а не самого оператора +.
Джеффри Хантин,
118

На самом деле, унарный плюс это сделать что - то - даже в 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);
}

Это отобразит «x is an int».

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

Чарльз Сальвия
источник
5
если вы пишете код, который дает заданный результат, когда заданы short и int, которые сравнивают равные, то у вас, вероятно, другая проблема
Ли Райан
1
Спасибо, это проясняет (примечание: в C я не смог заставить пример работать, так как я не могу перегрузить функцию foo)
Binarian
что это значит, говоря an integer of greater width?
yekanchi
в этом контексте «ширина» относится к количеству байтов памяти, связанных со значением.
giles
41

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

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

Клаудиу
источник
6
Абсолютно. * Это историческая причина. C ++ пришлось адаптировать его, поэтому пришлось иметь дело с перегрузкой.
Wolf
37

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

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

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

коричневый
источник
8
Я тоже делал это, особенно когда имел дело с векторами, такими какvec3(+1,-1,-1)
mpen
28

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

int x;
&x;

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

&+x;

:)

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

Муравей
источник
14

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

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

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

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

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

jkerian
источник
12

Если вам когда-нибудь понадобится распечатать числовое значение необработанных байтов (например, небольшие числа, сохраненные как char) для отладки или по любой другой причине, 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

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

Нику Стюрка
источник
4

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

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

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

ndkrempel
источник
3

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

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

Евро Мичелли
источник
3

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

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

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

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

Дэвид Торнли
источник
1
Единственная неарифметическая перегрузка, которая имеет смысл, связана с регулярными выражениями или грамматиками, где (+ термин) означает одну или несколько команд. (Это довольно стандартный синтаксис регулярных выражений)
Майкл Андерсон,
О entry: ( stackoverflow.com/q/254395/153285 ). В наши дни, если вам нужно несколько точек входа, просто используйте хвостовые вызовы и оптимизацию на основе профиля.
Potatoswatter
Я считаю, что даже в C99, учитывая extern volatile int foo;, что компилятор с данным оператором +foo;должен будет выполнить чтение указанного адреса на любой платформе, где предположительно могут существовать какие-либо средства для определения того, что чтение имело место. Я не уверен, что это потребовалось бы, если бы оператор был просто "foo", хотя многие компиляторы сделают это из любезности.
supercat
2

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

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

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

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

Хосе Ладейра
источник
-1

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

Патрик
источник
Это сделало бы его не противоположным унарному минусу, который сбивал бы с толку, если бы вы также не перегрузили унарный минус, чтобы он был отрицательным абс, что сделало бы все виды математических вещей странными
Дэви8
Ага. Вот почему я посоветовал этого не делать.
Патрик
1
@ Davy8: Что заставляет вас думать, что унарный плюс в настоящее время "противоположен" унарному минусу? Что «противоположно» оператору поразрядного дополнения ~? Я не уверен, каково ваше определение «противоположности», но подозреваю, что оно основано на опыте того, что в настоящее время делают унарный плюс и унарный минус.
ndkrempel
-1

РЕДАКТИРОВАТЬ Переписано полностью, потому что в моем первоначальном ответе я был 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; }
    }
}
Майкл Медоуз
источник
Мне это не кажется одинарной операцией. Он принимает два аргумента (апрель и май), чтобы быть двоичным.
BlueMonkMN,
Это бинарный плюс. Унарный плюс - это просто «+1» или что-то в этом роде, без левого операнда.
Джеффри Хантин,
моя вина. забыл свой CS101. фиксированный.
Майкл Медоуз,
3
Если бы я обнаружил такую ​​перегрузку в производственном коде, я бы обязательно пометил это как ошибку и исправил бы как можно скорее. Семантика +не в том, чтобы сделать значение положительным, а оставить его знак неизменным.
Артуро Торрес Санчес
-1

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

например;

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})
Brazz_Achi
источник