C # ma funkcję składni, w której można łączyć wiele typów danych w jednym wierszu.
string s = new String();
s += "Hello world, " + myInt + niceToSeeYouString;
s += someChar1 + interestingDecimal + someChar2;
Jaki byłby odpowiednik w C ++? O ile widzę, musiałbyś to wszystko zrobić w osobnych wierszach, ponieważ nie obsługuje wielu ciągów / zmiennych z operatorem +. To jest w porządku, ale nie wygląda tak schludnie.
string s;
s += "Hello world, " + "nice to see you, " + "or not.";
Powyższy kod powoduje błąd.
c++
string
compiler-errors
concatenation
Nick Bolton
źródło
źródło
char *
do siebie wskaźniki. To właśnie generuje błąd - ponieważ sumowanie wskaźników jest bezsensowne. Jak zauważono poniżej, zmień co najmniej pierwszy operand na anstd::string
i nie ma żadnego błędu.Odpowiedzi:
Zapoznaj się z artykułem Guru Tygodnia autorstwa Herb Sutter: The String Formatters of Manor Farm
źródło
std::string s = static_cast<std::ostringstream&>(std::ostringstream().seekp(0) << "HelloWorld" << myInt << niceToSeeYouString).str();
std::stringstream ss; ss << "Hello, world, " << myInt << niceToSeeYouString; std::string s = ss.str();
jest prawie jednoliniowyZa 5 lat nikt nie wspomniał
.append
?źródło
s.append("One"); s.append(" line");
s.append("One").append(" expression");
Może powinienem edytować oryginał, aby w ten sposób używał wartości zwracanej?s
w innym wierszu w równoważnym kodzie C # oraz w swoim niekompilującym się kodzie C ++. Jego pożądany C ++ tos += "Hello world, " + "nice to see you, " + "or not.";
coś, co można napisaćs.append("Hello world, ").append("nice to see you, ").append("or not.");
append
jest to, że działa również, gdy łańcuchy zawierają znaki NUL.Te literały tablicy znaków nie są C ++ std :: strings - musisz je przekonwertować:
Aby przekonwertować wartości typu int (lub dowolny inny typ nadający się do przesyłania strumieniowego), możesz użyć doładowania lexical_cast lub zapewnić własną funkcję:
Możesz teraz powiedzieć na przykład:
źródło
string("Hello world")
są wykonywane za pomocąoperator+()
zdefiniowanego w klasiestring
. Jeślistring
w wyrażeniu nie ma przedmiotu, konkatenacja staje się zwykłą sumą wskaźników znakówchar*
.Twój kod można zapisać jako 1 ,
... ale wątpię, że tego właśnie szukasz. W twoim przypadku prawdopodobnie szukasz strumieni:
1 " można zapisać jako ": Działa to tylko w przypadku literałów łańcuchowych. Łączenie jest wykonywane przez kompilator.
źródło
const char smthg[] = "smthg"
: / Czy to błąd?#define
swojego ciągu znaków, aby to obejść, chociaż powoduje to własne problemy.Używanie literałów zdefiniowanych przez użytkownika w C ++ 14 i
std::to_string
kod staje się łatwiejszy.Zauważ, że konkatenację literałów ciągów można wykonać w czasie kompilacji. Po prostu usuń
+
.źródło
std::literals::string_literals
pojęcia UDL, a nie do niego.Aby zaoferować rozwiązanie, które jest bardziej
concat
jednokreskowe : Można zaimplementować funkcję, aby zredukować „klasyczne” rozwiązanie oparte na ciągach znaków do pojedynczej instrukcji . Opiera się na zróżnicowanych szablonach i perfekcyjnym spedycji.Stosowanie:
Realizacja:
źródło
W C ++ 20 będziesz potrafił:
Do tego czasu możesz zrobić to samo z biblioteką {fmt} :
Zastrzeżenie : jestem autorem {fmt}.
źródło
boost :: format
lub std :: stringstream
źródło
Rzeczywistym problemem było to, że złączenie literały ciągów
+
nie w C ++:W C ++ (również w C) łączysz literały ciągów, umieszczając je tuż obok siebie:
Ma to sens, jeśli generujesz kod w makrach:
... proste makro, którego można używać w ten sposób
( demo na żywo ... )
lub, jeśli nalegasz na użycie
+
literałów ciągów for (jak już zasugerowano przez podkreślenie_d ):Inne rozwiązanie łączy ciąg i znak
const char*
dla każdego kroku konkatenacjiźródło
sprintf
jest oczywiście opcją, ale jest też std :: stringstream, który zapobiega problemom z niewymiarowymi buforami.źródło
Musiałbyś zdefiniować operator + () dla każdego typu danych, który chciałbyś skoncentrować w łańcuchu, ale ponieważ operator << jest zdefiniowany dla większości typów, powinieneś użyć std :: stringstream.
Cholera, pobij o 50 sekund ...
źródło
std::string operator+(std::string s, int i){ return s+std::to_string(i); }
Jeśli napiszesz
+=
, wygląda prawie tak samo jak C #źródło
Jak powiedzieli inni, głównym problemem z kodem OP jest to, że operator
+
nie konkatenujeconst char *
; ale to działastd::string
.Oto inne rozwiązanie, które używa lambd C ++ 11
for_each
i pozwalaseparator
na rozdzielenie ciągów znaków:Stosowanie:
Wydaje się, że skaluje się dobrze (liniowo), przynajmniej po szybkim teście na moim komputerze; oto krótki test, który napisałem:
Wyniki (w milisekundach):
źródło
Może podoba Ci się moje rozwiązanie „Streamer”, które naprawdę robi to w jednej linii:
źródło
Oto rozwiązanie jednowierszowe:
Chociaż jest trochę brzydki, myślę, że jest mniej więcej tak czysty jak kot w C ++.
Rzucamy pierwszy argument na a,
std::string
a następnie używamy kolejności oceny (od lewej do prawej),operator+
aby upewnić się, że jego lewy argument jest zawsze astd::string
. W ten sposób łączymy operand postd::string
lewej stronie zconst char *
operandem po prawej stronie i zwracamy innystd::string
, kaskadowo efekt.Uwaga: istnieje kilka opcji dla prawego argumentu, w tym
const char *
,std::string
ichar
.Do Ciebie należy decyzja, czy magiczna liczba to 13 czy 6227020800.
źródło
W tym celu możesz użyć tego nagłówka: https://github.com/theypsilon/concat
Pod maską będziesz używać std :: ostringstream.
źródło
Jeśli chcesz użyć
c++11
, możesz użyć literałów ciągów zdefiniowanych przez użytkownika i zdefiniować dwa szablony funkcji, które przeciążają operator plus dlastd::string
obiektu i dowolnego innego obiektu. Jedyną pułapką jest nieprzeciążanie operatorów plusstd::string
, w przeciwnym razie kompilator nie wie, którego operatora użyć. Możesz to zrobić za pomocą szablonustd::enable_if
ztype_traits
. Po tym ciągi zachowują się tak jak w Javie lub C #. Zobacz moją przykładową implementację po szczegóły.Kod główny
Plik c_sharp_strings.hpp
Dołącz ten plik nagłówkowy we wszystkich miejscach, w których chcesz mieć te ciągi.
źródło
Coś takiego działa na mnie
źródło
W oparciu o powyższe rozwiązania stworzyłem klasę var_string dla mojego projektu, aby ułatwić życie. Przykłady:
Sama klasa:
Wciąż zastanawiasz się, czy w C ++ będzie coś lepszego?
źródło
W c11:
pozwala to na tworzenie wywołań funkcji w ten sposób:
wypisze: numer wiadomości: 10
źródło
możesz także "rozszerzyć" klasę string i wybrać preferowany operator (<<, &, |, etc ...)
Oto kod wykorzystujący operator <<, aby pokazać, że nie ma konfliktu ze strumieniami
uwaga: jeśli odkomentujesz s1.reserve (30), są tylko 3 żądania operatora new () (1 dla s1, 1 dla s2, 1 dla rezerwacji; niestety nie możesz zarezerwować w czasie konstruktora); bez zastrzeżeń, s1 musi żądać więcej pamięci, gdy rośnie, więc zależy to od współczynnika wzrostu implementacji twojego kompilatora (w tym przykładzie wydaje się, że moje jest 1,5, 5 wywołań new ())
źródło
Strumień łańcuchowy z prostym makrem preprocessora używającym funkcji lambda wydaje się fajny:
i wtedy
źródło
To działa dla mnie:
Wynik:
źródło
const
lub (jeśli wymagana jest zerowa pamięć masowa)enum
?Czy próbowałeś uniknąć + =? zamiast tego użyj var = var + ... to zadziałało dla mnie.
źródło
#include <iostream.h> // string
#include <system.hpp> // ansiString