Co robi operator jednoargumentowy plus?

86

Co robi operator jednoargumentowy plus? Jest kilka definicji, które znalazłem ( tu i tutaj ), ale nadal nie mam pojęcia, do czego miałoby to służyć. Wygląda na to, że nic nie robi, ale jest ku temu powód, prawda?

vrish88
źródło
3
Myślę, że historyczny powód jest poważnie niedoceniany.
Wolf
3
Pytanie z trzema różnymi tagami językowymi jest dość niejednoznaczne / złe! Odpowiedzi są bardzo różne dla C # (z możliwością przeciążenia) i C (bez przeciążania) i C ++ (z możliwością przeciążenia, ale dziedziczy to z języka C, a zatem również z jego właściwości).
legends2k
Chciałbym dodać link do 10 głównych błędów C # Erica Lipperta. Operator jednoargumentowy plus znajdziesz w wyróżnieniach: informit.com/articles/article.aspx?p=2425867 Mówi on po prostu, że powinien zostać usunięty lub nigdy nie powinien zostać dodany.
Noel Widmer

Odpowiedzi:

57

Jest tam, aby być przeciążonym, jeśli poczujesz potrzebę; dla wszystkich predefiniowanych typów jest to w zasadzie zakaz.

Praktyczne zastosowania jednoargumentowego operatora arytmetycznego no-op są dość ograniczone i zwykle odnoszą się do konsekwencji użycia wartości w wyrażeniu arytmetycznym, a nie samego operatora. Na przykład można jej użyć do wymuszenia poszerzenia z mniejszych typów całkowitych do intlub zapewnienia, że ​​wynik wyrażenia jest traktowany jako wartość r, a zatem nie jest zgodny z constparametrem nie będącym referencją. Uważam jednak, że te zastosowania lepiej nadają się do kodowania golfa niż do czytelności. :-)

Jeffrey Hantin
źródło
7
W rzeczywistości nie jest to prawdą, jak wskazuje kilka poniższych przykładów.
jkerian
3
Dobra, kupię, że ma pewne zastosowania, ale większość zastosowań omówionych poniżej dotyczy faktu, że jest to wyrażenie numeryczne zbudowane przy użyciu operatora no-op: na przykład promowanie inti skutkujące rvalue są efektami wyrażenia -ness, a nie samego operatora +.
Jeffrey Hantin,
118

W rzeczywistości jednoargumentowy plus robi coś - nawet w C. Wykonuje zwykłe konwersje arytmetyczne na operandzie i zwraca nową wartość, która może być liczbą całkowitą o większej szerokości. Jeśli oryginalna wartość była liczbą całkowitą bez znaku o mniejszej szerokości niż int, zostanie również zmieniona na signedwartość.

Zwykle nie jest to aż tak ważne, ale może mieć wpływ, więc nie jest dobrym pomysłem używanie jednoargumentowego plusa jako pewnego rodzaju „komentarza” oznaczającego, że liczba całkowita jest dodatnia. Rozważmy następujący program w 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);
}

Spowoduje to wyświetlenie „x to int”.

Więc w tym przykładzie jednoargumentowy plus utworzył nową wartość z innym typem i podpisem.

Charles Salvia
źródło
5
jeśli piszesz kod, który daje podany wynik, gdy otrzymujesz krótki i int, które porównują równe, to prawdopodobnie masz inny problem
Lie Ryan
1
Dzięki, to wyjaśnia (uwaga: w C nie mogłem uruchomić przykładu, ponieważ nie mogę przeciążyć funkcji foo)
Binarian,
co to znaczy mówiąc an integer of greater width?
yekanchi
w tym kontekście „szerokość” odnosi się do liczby bajtów pamięci związanej z wartością.
giles
41

Z drugiej edycji K&R:

Jednoargumentowy + jest nowością w standardzie ANSI. Został dodany dla symetrii z jednoargumentowym -.

Claudiu
źródło
6
Absolutnie. * To jest historyczny powód. C ++ musiał to dostosować, więc musiał radzić sobie z przeciążeniem.
Wilk
37

Widziałem, że jest używany dla jasności, aby podkreślić wartość dodatnią w odróżnieniu od wartości ujemnej:

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

Ale to dość słabe zastosowanie. Odpowiedź jest zdecydowanie przeładowana.

brązowy
źródło
8
Ja też to zrobiłem, zwłaszcza gdy mam do czynienia z wektorami takimi jakvec3(+1,-1,-1)
mpen
28

Jedną z rzeczy, które +robi wbudowana jednostka jednoargumentowa , jest zamiana lvalue na rvalue. Na przykład możesz to zrobić

int x;
&x;

ale nie możesz tego zrobić

&+x;

:)

PS „Przeciążanie” zdecydowanie nie jest właściwą odpowiedzią. Jednoargumentowe +zostało odziedziczone z C i nie ma przeciążenia operatora na poziomie użytkownika w C.

Mrówka
źródło
14

Najważniejsze, co osiąga + unary, to promocja typu na int dla typów danych mniejszych niż int. Może to być bardzo przydatne, jeśli próbujesz wydrukować dane typu char std::coutjako dane liczbowe.

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

bardzo różni się od

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

Jest również dostępny do przeciążania, ale w praktyce przeciążenie powinno wynosić prawie NOP.

jkerian
źródło
12

Jeśli kiedykolwiek będziesz musiał wydrukować wartość liczbową surowych bajtów (np. Małe liczby przechowywane jako znaki) w celu debugowania lub z jakiegokolwiek powodu, jednoargumentowe + może uprościć kod drukowania. Rozważać

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

To tylko szybki przykład. Jestem pewien, że są inne przypadki, kiedy jednoargumentowe + może pomóc traktować twoje bajty bardziej jak liczby, a nie jak tekst.

Nicu Stiurca
źródło
4

Ciekawostka historyczna. Komitet normalizacyjny C99 również uważał, że istniejące zastosowania unarnikowego plusa są dość rzadkie, o czym świadczy rozważenie ponownego użycia go w celu osiągnięcia innej cechy w języku: zahamowania oceny czasu tłumaczenia stałych wyrażeń zmiennoprzecinkowych. Patrz następujący cytat z uzasadnienia C, sekcja F.7.4:

Wczesna wersja tej specyfikacji pozwalała na arytmetykę stałej czasu translacji, ale umożliwiała jednoargumentowy operator +, gdy jest stosowany do operandu, do powstrzymywania obliczania stałych wyrażeń w czasie tłumaczenia.

Ostatecznie semantyka została odwrócona, z oceną w czasie wykonywania wymuszoną w większości kontekstów (przynajmniej do reguły „jak gdyby”) i możliwością wymuszenia oceny czasu tłumaczenia za pomocą statycznych inicjatorów. Zauważ, że główna różnica polega na występowaniu wyjątków zmiennoprzecinkowych i innych ustawieniach zaokrąglania zmiennoprzecinkowego lub precyzji, jeśli są obecne.

ndkrempel
źródło
3

Niewiele. Ogólnym argumentem przemawiającym za zezwoleniem na przeciążenie operator+()jest to, że zdecydowanie istnieją rzeczywiste zastosowania przeciążania operator-()i byłoby bardzo dziwne (lub asymetryczne), gdybyś pozwolił na przeciążenie, operator-()ale nie operator+().

Wydaje mi się, że najpierw przeczytałem ten argument od Stroustropa, ale nie mam przy sobie moich książek, aby to zweryfikować. Mogę się mylić.

Euro Micelli
źródło
3

Unary plus był obecny w C, gdzie nie robił absolutnie nic (podobnie jak autosłowo kluczowe). Aby go nie mieć, Stroustrup musiałby wprowadzić nieuzasadnioną niezgodność z C.

Kiedyś był w C ++, naturalne było zezwolenie na funkcję przeciążającą, taką jak jednoargumentowy minus, i Stroustrup mógł ją wprowadzić z tego powodu, gdyby jeszcze jej tam nie było.

Więc to nic nie znaczy. Może być używany jako rodzaj dekoracji, aby rzeczy wyglądały bardziej symetrycznie, używając na przykład +1,5 jako przeciwieństwa do -1,5. W C ++ może być przeciążony, ale może być mylący, jeśli operator+()coś zrobi. Pamiętaj o standardowej zasadzie: przeciążając operatory arytmetyczne, rób rzeczy takie jak ints.

Jeśli szukasz powodu, dla którego tam jest, znajdź coś o wczesnej historii C. Podejrzewam, że nie było dobrego powodu, ponieważ C nie został tak naprawdę zaprojektowany. Rozważ bezużyteczne autosłowo kluczowe (prawdopodobnie w przeciwieństwie do tego static, które jest teraz odtwarzane w C ++ 0x) i entrysłowo kluczowe, które nigdy nic nie zrobiło (a później zostało pominięte w C90). Jest słynny e-mail, w którym Ritchie lub Kernighan mówią, że kiedy zdali sobie sprawę, że pierwszeństwo operatorów ma problemy, istniały już trzy instalacje z tysiącami linii kodu, których nie chcieli złamać.

David Thornley
źródło
1
Jedynym niearytmetycznym przeciążeniem, które widziałem, które ma sens, było wyrażenia regularne lub gramatyki, w których (+ termin) oznacza jedno lub więcej temów. (Co jest dość standardową składnią wyrażeń regularnych)
Michael Anderson,
Informacje entry: ( stackoverflow.com/q/254395/153285 ). W dzisiejszych czasach, jeśli chcesz mieć wiele punktów wejścia, po prostu użyj wywołań końcowych i optymalizacji sterowanej profilem.
Potatoswatter
Uważam, że nawet w C99, biorąc pod uwagę extern volatile int foo;, kompilator, który otrzyma instrukcję, +foo;byłby zobowiązany do wykonania odczytu wskazanego adresu na dowolnej platformie, na której możliwe byłoby istnienie jakichkolwiek środków, aby stwierdzić, że odczyt miał miejsce. Nie jestem pewien, czy byłoby to wymagane, gdyby instrukcja zawierała po prostu "foo", chociaż wielu kompilatorów zrobi to grzecznościowo.
supercat
2

Nie mogę cytować żadnego źródła tego, ale zrozumiałem, że dotyczy to jawnej promocji typu, co oznacza bezstratną konwersję typów. To stawia go na szczycie hierarchii konwersji,

  • Awans: new_type operator+(old_type)
  • Konwersja: new_type(old_type)
  • Odlew: operator(new_type)(old_type)
  • Przymus: new_type operator=(old_type)

Oczywiście wynika to z mojej interpretacji notatki w jednym z (naprawdę starych) podręczników c / c ++ firmy Microsoft, które przeczytałem około 15 lat temu, więc traktuj to z przymrużeniem oka.

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

Jak pokazano w powyższym przykładzie, jednoargumentowy + naprawdę zmienia typ, odpowiednio rozmiar 4 i 2. Dziwne, że wyrażenie + x jest rzeczywiście obliczane w rozmiarze sizeof, pomyślałem, że nie powinno. Być może wynika to z faktu, że sizeof ma taki sam priorytet jak jednoargumentowe +.

Jose Ladeira
źródło
-1

Przypuszczam, że możesz go użyć, aby zawsze uzyskać dodatnią liczbę. Po prostu przeładuj jednoargumentowy operator +, aby był abs. Naprawdę nie warto mylić innych programistów, chyba że naprawdę chcesz zaciemnić swój kod. Wtedy będzie dobrze działać.

Patrick
źródło
To nie byłoby przeciwieństwem jednoargumentowego minus, co byłoby mylące, chyba że przeładujesz również jednoargumentowy minus, aby był ujemnym abs, co spowodowałoby, że wszystkie rodzaje matematyki
byłyby
Tak, tak. Dlatego zasugerowałem, żeby tego nie robić.
Patrick,
1
@ Davy8: Co sprawia, że ​​myślisz, że jednoargumentowy plus jest obecnie "przeciwieństwem" jednoargumentowego minusa? Jakie jest „przeciwieństwo” operatora dopełniacza bitowego ~? Nie jestem pewien, jaka jest twoja definicja „przeciwieństwa”, ale podejrzewam, że jest ona obciążona doświadczeniem tego, co obecnie robią jednoargumentowy plus i jednoargumentowy minus.
ndkrempel
-1

EDYCJA Przepisałem całkowicie, bo waaaayyy w mojej oryginalnej odpowiedzi.

Powinno to pozwolić ci obsłużyć jawną deklarację twojego typu jako wartość dodatnią (myślę, że w większości operacji niematematycznych). Wydaje się, że negacja byłaby bardziej przydatna, ale wydaje mi się, że oto przykład, gdzie może mieć znaczenie:

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; }
    }
}
Michael Meadows
źródło
Dla mnie to nie wygląda na jednoargumentową operację. Potrzeba dwóch argumentów (kwiecień i maj), aby były binarne.
BlueMonkMN
To binarny plus. Jednoargumentowy plus to po prostu „+1” lub coś takiego, bez lewego operandu.
Jeffrey Hantin
mój błąd. zapomniałem mojego CS101. naprawiony.
Michael Meadows,
3
Gdybym znalazł tego rodzaju przeciążenie w kodzie produkcyjnym, na pewno oznaczyłbym to jako błąd i naprawiłbym go jak najszybciej. Semantyka +nie polega na nadaniu wartości dodatniej, ale na pozostawieniu jej znaku bez zmian.
Arturo Torres Sánchez
-1

po prostu to służyło do przekonania, które liczby są dodatnie

na przykład;

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
źródło