Przeciążanie przecinka

2008-07-31 16:34

Przecinek to taki niepozorny znak, którego grubo ponad 90% zastosowań ogranicza się zapewne do oddzielania parametrów funkcji (czy to w deklaracji, czy to w wywołaniu). Niektóre języki używają też go do separowania indeksów wielowymiarowych tablic, ale do nich C++ akurat nie należy.
Zamiast tego przecinek jest tam operatorem, o czym rzadko się pamięta. Być może dlatego, że ma on najniższy priorytet spośród wszystkich operatorów. Wydaje się też, że domyślne jego działanie (obliczenie wszystkich argumentów, a następnie zwrócenie ostatniego) nie jest specjalnie przydatne – jeśli w ogóle.

Można je jednak zmienić. Tak, tak – operator przecinka można przeciążać, jakkolwiek zaskakujące i przekombinowane by się to wydawało. W rzeczywistości jest on bowiem zwyczajnym operatorem binarnym o łączności lewostronnej i wspomnianym najniższym priorytecie. A przeciążyć można go, pisząc funkcję operator,() – dokładnie tak samo, jak każdego innego dwuargumentowego operatora.
Do czego może to służyć? Otóż względnie typową sztuczką jest użycie przedefiniowanego przecinka do konstrukcji obiektów złożonych z wielu elementów, np. wektorów lub macierzy. Oto przykład przeciążenia dla standardowej klasy vector:

  1. #include <vector>
  2. template <typename T> std::vector<T> operator , (std::vector<T> v, const T& obj)
  3. {
  4.     v.push_back (obj);
  5.     return v;
  6. }

Pozwala to na inicjalizację wektora w taki oto nietypowy sposób:

  1. std::vector<int> ints = (std::vector<int>(), 1, 2, 3, 4, 5);

Pierwszy element tego ciągu (pusty wektor) jest konieczny, gdyż w przeciwnym razie użyty zostałby standardowy operator przecinka.

Na pierwszy rzut może to wyglądać efektownie. Pamiętajmy jednak, że przecinek ten pozostaje wciąż przecinkiem, zachowując chociażby swoją główną cechę szczególną, czyli priorytet. W szczególności próba dodania do wektora kolejnych elementów w ten sposób:

  1. ints = ints, 6, 7, 8, 9;

zakończy się niezupełnie po naszej myśli…
Mimo to być może warto spróbować wymyślić dla tego operatora jakieś własne, w miarę sensowne zastosowanie. Możliwe, że okaże się on wcale nie tak nieużyteczny, na jakiego zdaje się wyglądać :]

Tags: , ,
Author: Xion, posted under Programming »


4 comments for post “Przeciążanie przecinka”.
  1. Gynvael:
    July 31st, 2008 o 17:34

    Hahaha świetny pomysł ;>

  2. losiu99:
    August 3rd, 2008 o 20:01

    Pomysł na przeciążenie, nie da się ukryć, oryginalny :D Nigdy nie mogłem wymyślić dla niego jakiegoś sensownego zastosowania, a tu patrz…
    Niemniej jednak obawiam się, że w pierwszym przypadku również nie stanie się to, o co Ci chodzi, właśnie przez priorytet przecinka:
    Wykonane zostanie przypisanie, potem przeciążony przecinek weźmie PRZEZ WARTOŚĆ jego wynik, doda, po czym zwróci jeszcze inny obiekt. Tzn. wykonane zostałoby itp., gdyby to nie była inicjalizacja- sprawdzałem ten kod na VC++ 2008 EE i się nie kompiluje: error C2059: syntax error : ‘constant’
    Oczywiście nawiasy usuwają problem. Obydwie formy działają natomiast, jeśli zamiast przez wartość będziemy przyjmować/zwracać vector przez referencję. Nie zmienia to jednak faktu, że pomysł sam w sobie jest świetny, choć nie wiem, czy się przyjmie :P
    Pozdrawiam, mam nadzieję że niczego nie pokręciłem. Nade wszystko jednak gratuluję wyobraźni :D

  3. Xion:
    August 4th, 2008 o 0:01

    Faktycznie trochę za bardzo uwierzyłem w zdolności analizatora składniowego w VC++. Teoretycznie powinien bez problemu stwierdzić, że ma doczynienia z deklaracją + inicjalizacją zmiennej, ale widać w praktyce różnie z tym bywa :) (Prawdopodobnie jest to zresztą zachowanie standardowe). Dla porządku poprawiłem już ten przykład.

    Natomiast sam pomysł na przeciążanie przecinka nie jest wcale oryginalny; widziałem go przynajmniej w jednej bibliotece matematycznej, tyle że już zapomniałem, w której :)

  4. l30n:
    August 16th, 2008 o 15:14

    Cale szczesice w C++0x (o ile kiedykolwiek ten standard bedzie obslugiwany :P) beda juz konstruktury listowe, wiec bedzie mozna zrobic jak bog przykazal:

    vector V = { 1, 2, 3 };

Comments are disabled.
 


© 2017 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.