Що робить оператор unary plus?


86

Що робить оператор unary plus? Є кілька визначень, які я знайшов ( тут і тут ), але я досі не уявляю, для чого це буде використовуватися. Здається, це нічого не робить, але на це є причина, так?


3
Я думаю, що історична причина сильно занижена.
Вовк

3
Питання з трьома різними мовними тегами досить неоднозначне / погане! Відповіді дуже різні для C # (завантажуваний) та C (без перевантаження) та C ++ (завантажуваний, але успадковує це від C, а отже, і його властивості).
legends2k

Я хотів би додати посилання на 10 головних недоліків C # Еріка Ліпперта. Оператор unary plus ви знайдете в почесних згадках: informit.com/articles/article.aspx?p=2425867 В основному він каже, що його слід видалити або його ніколи не слід додавати.
Ноель Відмер

Відповіді:


57

Це є для перевантаження, якщо ви відчуваєте потребу; для всіх попередньо визначених типів це, по суті, заборона.

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


7
Це насправді не відповідає дійсності, на що вказують кілька прикладів нижче.
jkerian

3
Добре, я придбаю, що він має деякі способи використання, але більшість обговорень нижче стосуються того факту, що це числовий вираз, побудований за допомогою оператора no-op: наприклад, просування до intі значення rvalue є ефектами вираження -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 - це int".

Отже, у цьому прикладі унарний плюс створив нове значення з іншим типом та підписом.


5
якщо ви пишете код, який дає заданий результат, коли дається короткий і int, який порівнює рівне, то у вас, мабуть, інша проблема
Lie Ryan

1
Дякую, це дає зрозуміти (sidenote: У C я не міг змусити приклад працювати, оскільки я не можу перевантажити функцію foo)
Binarian

що це означає, кажучи an integer of greater width?
єканчі

у цьому контексті "ширина" відноситься до кількості байтів пам'яті, пов'язаних зі значенням.
giles

41

З другого видання K&R:

Унарний + є новим для стандарту ANSI. Це було додано для симетрії з одинарним -.


6
Абсолютно. * Це історична причина. C ++ повинен був його адаптувати, тому йому довелося мати справу з перевантаженням.
Вовк

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. Це може бути дуже корисно, якщо ви намагаєтесь надрукувати дані символів, використовуючи std::coutцифрові дані.

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

сильно відрізняється від

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

Він також доступний для перевантаження, але на практиці ваше перевантаження має бути майже NOP.


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

Це лише короткий приклад. Я впевнений, бувають інші випадки, коли unary + може допомогти розглядати ваші байти більше як цифри, а не як текст.


4

Історичний ласощі. Комітет стандартизації C99 також вважав, що існуючі варіанти використання унарних плюсів були досить рідкісними, про що свідчить їх розгляд можливості повторного використання його для досягнення ще однієї особливості мови: гальмування оцінки часу перекладу константних виразів із плаваючою комою. Див. Наступну цитату з обґрунтування С, розділ F.7.4:

Рання версія цієї специфікації дозволяла арифметику константи часу перекладу, але надала можливість оператору unary +, коли застосовується до операнда, перешкоджати оцінці часу перекладу константних виразів.

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


3

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

Я вважаю, що вперше прочитав цей аргумент у "Строустроп", але не маю при собі своїх книг для підтвердження. Я можу помилятися.


3

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

Як тільки це було в C ++, було природно дозволити функцію перевантаження, як і одинарний мінус, і Stroustrup міг би ввести її з цієї причини, якби її там ще не було.

Отже, це нічого не означає. Він може бути використаний як вид прикраси, щоб зробити речі більш симетричними, використовуючи +1,5, як протилежність -1,5, наприклад. У C ++ він може бути перевантажений, але це буде заплутати, якщо operator+()щось зробить. Запам’ятайте стандартне правило: перевантажуючи арифметичні оператори, виконуйте такі дії, як ints.

Якщо ви шукаєте причину, чому вона там, знайдіть щось про ранню історію 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)

Звичайно, це з моєї інтерпретації примітки в одному з посібників для Microsoft (справді старого) c / c ++, який я читав близько 15 років тому, тож сприйміть це з достатньою кількістю солі.


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

Як показано у прикладі вище, unary + дійсно змінює тип, розміри 4 та 2 відповідно. Дивно, що вираз + x справді обчислюється в розміріof, я думав, що це не повинно було. Можливо, це пов'язано з тим, що sizeof має такий же пріоритет, як і unary +.


-1

Думаю, ви могли б використовувати його, щоб завжди зробити число позитивним. Просто перевантажте унарний + оператор, щоб бути абс. Насправді не варто плутати колег-розробників, якщо ви насправді просто не хочете заплутати свій код. Тоді це добре працювало б.


Це зробило б не протилежність одинарному мінусу, який би заплутав, якщо ви також не перевантажите одинарний мінус тим негативним абс, який зробить всі математичні речі
дивними

Так, так. Тому я запропонував цього не робити.
Патрік

1
@ Davy8: Що змушує вас думати, що одинарний плюс зараз є "протилежністю" одинарного мінуса? Що є "протилежністю" побітового оператора доповнення ~? Я не впевнений, що таке ваше визначення "протилежне", але я підозрюю, що це упереджено досвідом того, що в даний час роблять одинарний плюс і одинарний мінус.
ndkrempel

-1

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

Для мене це не схоже на одинарну операцію. Потрібні два аргументи (квітень і травень), щоб це було двійковим способом.
BlueMonkMN

Це двійковий плюс. Одинарний плюс - це просто "+1" або будь-який інший, без лівого операнда.
Джеффрі Хантін,

моє ліжко. забув свій CS101. виправлений.
Michael Meadows,

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})
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.