std::string VS rekurencja
Hey o/
Dziś będzie o tym, jak to pewien człowiek zmagał się z funkcją rekurencyjną która zwraca stringa…
Ale do rzeczy. Ostatnio przypominając sobie rekurencję, na przykładzie funkcji która zamienia liczbę (przy założeniu że jest ona podana w systemie decymalnym) na jej binarny odpowiednik, wpadłem na pomysł… „A dlaczego by tak nie zwrócić stringa ?”.
No tak, tylko po co ? Po co taka funkcja miałaby zwracać obiekt klasy string, skoro można prościej, np intem.
Niby można, ale przecież warto się pobawić 😉 Dodam, że oczywiście sam nie wpadłem na ten genialny pomysł, bo wpadł na niego Unavowed 😉
Ok, załóżmy że funkcja zwracająca int’a w tym przypadku mogłaby wyglądać mniej więcej tak:
int bin(int n)
{
int rest = n%2;
if(rest >= 1)
bin(n/2);
else
printf("%i",0);
return rest;
}
Ofc powyższy kod nie ma jakichkolwiek zabezpieczeń przed integer overflow’ami itp, oraz zakłada że przekażemy funkcji liczbę w mniemaniu decymalnej.
Super, a teraz warto się zastanowić jak ta funkcja mogłaby wyglądać gdybyśmy chcieli zwrócić std::string.
Pierwsze co rzuca się na myśl początkującym programistom to pewnie:
string bin(int n)
{
string rest;
if(n>=1)
bin(n/2);
return rest;
}
Nawet jeśli z logicznego pkt widzenia ten kod może się wydawać prawidłowy, to kompilator i tak zaprotestuje pod pretekstem:
bin.cpp: In function ‘std::string bin(int)’:
bin.cpp:15:19: error: invalid conversion from ‘int’ to ‘const char*’ [-fpermissive]
/usr/include/c++/4.6/bits/basic_string.tcc:214:5: error: initializing argument 1 of ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char, _Traits = std::char_traits, _Alloc = std::allocator]’ [-fpermissive]
Kłania się semantyka C++, bo nie można sobie od tak do stringa wpisać int’a .
Pod systemami z rodziny Windows zapewne jest funkcja (nienatywna) typu itoa, ale nie opłaca się z niej korzystać (bo to chociażby nieładne :P), a jeśli nawet, to nie mam jej pod *unixami 😉
Nie ma lekko, trzeba coś wymyślić samemu.
Całe szczęście , w C++ są strumienie, a zwłaszcza strumienie stringów ;>
Całego tego nieszczęścia można uniknąć poprzez posłużenie się strumieniem stringów chociażby w taki sposób :
...
#include
...
string bin(int n)
{
osstream ss;
if(n>=1)
{
ss << bin(n/2);
ss << n%2;
}
return ss.str();
}
I po sprawie. Dzięki temu że do string streamu możemy zapisać zmienne niemal każdego typu, to potem możemy zawartość strumienia
przekonwertować do stringa, jednym prostym wywołaniem metody z klasy sstream
ss.str();
Mała rzecz, a może się przydać w wielu sytuacjach 😉