yhm :O
to zależy, co znaczy "lepiej" - w sam zapis rozumiem możemy ingerować, bo cała konwencja już ustalona: lista inicjalizacyjna, argumenty konstruktorów xów i ygreków? Jak tylko zapis, to ja osobiście bym nie wytrzymał:
#define _(t) strchr(t,',')
#define s(t) strspn(t, "0123456789.%")
#define cs(t) strcspn(t, "0123456789.%")
TArea( const char* strArea, int ilin ):
x1(
strArea + cs(strArea),
s(strArea + cs(strArea) ) ),
y1(
_(strArea) + cs(_(strArea)),
s(_(strArea) + cs(_(strArea))) ),
x2(
_(_(strArea)+1) + cs(_(_(strArea)+1)),
s(_(_(strArea)+1) + cs(_(_(strArea)+1)))
),
y2(
_(_(_(strArea)+1)+1) + cs(_(_(_(strArea)+1)+1)),
s(_(_(_(strArea)+1)+1) + cs(_(_(_(strArea)+1) +1)) )
)
{};
// dopisane (bo zapomniałem posprzątać):
#undef _
#undef s
#undef cs
przyznam szczerze, przed zastosowaniem define, to nie widziałem, że to takie ładne. zdaje się, można to by było uogólnić jakimś rekurencyjnym templatem (bo rozumiem, że zwykła funkcja rekurencyjna odpada z miejsca).
dopisane:
dobra, niech będzie widać ewolucję myśli mojej. po pierwsze, po dopisaniu szablonu nabiera to ludzkiego wyglądu:
template<int N>
inline const char* nchar(const char* text, int ch=',') {
return nchar<N-1>( strchr(text, ch) +1, ch );
}
template<>
inline const char* nchar<1>(const char* text, int ch) {
return strchr(text, ch);
}
template<>
inline const char* nchar<0>(const char* text, int ch) {
return text;
}
//----------------------------
TArea( const char* strArea, int ilin ):
x1(
nchar<0>(strArea) + cs(nchar<0>(strArea)),
s( nchar<0>(strArea) + cs(nchar<0>(strArea)) )
),
y1(
nchar<1>(strArea) + cs(nchar<1>(strArea)),
s( nchar<1>(strArea) + cs(nchar<1>(strArea)) )
),
x2(
nchar<2>(strArea) + cs(nchar<2>(strArea)),
s( nchar<2>(strArea) + cs(nchar<2>(strArea)) )
),
y2(
nchar<3>(strArea) + cs(nchar<3>(strArea)),
s( nchar<3>(strArea) + cs(nchar<3>(strArea)) )
)
{};
po drugie, teraz to już jak w pysk strzelił widać, że mamy z X razy wywoływane strchr na tych samych danych w kółko. I nie ma bata, zdrowy rozsądek mówi, że listę inicjalizacyjną olać i zrobić to w konstruktorze właściwym.
template<int N>
inline const char* skipsep(const char* text, int sep=',') { return strchr(text+1, sep); }
template<>
inline const char* skipsep<1>(const char* text, int sep) { return strchr(text, sep); }
template<>
inline const char* skipsep<0>(const char* text, int sep) { return text; }
TArea( const char* strArea, int ilin) {
const char* i = strArea;
size_t n;
static const char* nums = "0123456789.%";
n = strcspn( i=skipsep<0>(i), nums);
x1.first = i+n;
x1.second = strspn(i+n, nums);
n = strcspn( i=skipsep<1>(i), nums);
y1.first = i+n;
y1.second = strspn(i+n, nums);
n = strcspn( i=skipsep<2>(i), nums);
x2.first = i+n;
x2.second = strspn(i+n, nums);
n = strcspn( i=skipsep<3>(i), nums);
y2.first = i+n;
y2.second = strspn(i+n, nums);
}
w zasadzie tylko dla estetyki dodałem funkcję skipsep (nie jest ona w żadnym wypadku rekurencyjna). Na podstawie numeru 0,1,2,3,4,5 sama decyduje jak ten n-ty argument ominąć. Dla zerowego robi przypisanie, dla 1-szego strchr(text), dla nastęnych strchr(text+1). Dzięki temu te 4 bloki wyglądają niemal identycznie i (pozornie) proszą o pętlę. Ale wygląd to #@$ pies. Najważniejsze, że uniknęliśmy X-krotnych wywołań takiego samego strchr, strspn itp. Tylko konstruktor domyślny dla ygreków i xów zrób dobry (najlepiej pusty, nie będzie nawet zerował składowych - zero narzutu. Jak domyślny ci potrzebny do czego innego, to zrób taki:
struct MyX {
enum fastinit_type { fastinit };
MyX(fastinit_type) { }
// ...
}
i konstruktor "nasz" uzupełnij:
TArea( const char* strArea, int ilin) : x1(MyX::fastinit) /*itd...*/ {