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?
Odpowiedzi:
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 int
lub zapewnienia, że wynik wyrażenia jest traktowany jako wartość r, a zatem nie jest zgodny z const
parametrem nie będącym referencją. Uważam jednak, że te zastosowania lepiej nadają się do kodowania golfa niż do czytelności. :-)
int
i skutkujące rvalue są efektami wyrażenia -ness, a nie samego operatora +.
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 signed
wartość.
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.
an integer of greater width
?
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.
vec3(+1,-1,-1)
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.
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::cout
jako 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.
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.
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.
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ć.
Unary plus był obecny w C, gdzie nie robił absolutnie nic (podobnie jak auto
sł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 int
s.
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 auto
słowo kluczowe (prawdopodobnie w przeciwieństwie do tego static
, które jest teraz odtwarzane w C ++ 0x) i entry
sł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ć.
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.
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.
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,
new_type operator+(old_type)
new_type(old_type)
operator(new_type)(old_type)
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.
#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 +.
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ć.
~
? 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.
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; }
}
}
+
nie polega na nadaniu wartości dodatniej, ale na pozostawieniu jej znaku bez zmian.
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})