Mengapa tidak ada std :: stou?

96

C ++ 11 menambahkan beberapa fungsi konversi string baru:

http://en.cppreference.com/w/cpp/string/basic_string/stoul

Ini termasuk stoi (string ke int), stol (string ke long), stoll (string ke long long), stoul (string ke unsigned long), stoull (string ke unsigned long long). Terkemuka dalam ketidakhadirannya adalah fungsi stou (string to unsigned). Adakah alasan mengapa hal itu tidak diperlukan tetapi yang lainnya ada?

related: Tidak ada fungsi "sto {short, unsigned short}" di C ++ 11?

David Stone
sumber
6
Pertanyaan saya dimaksudkan agar lebih pada garis "apakah ada beberapa kelemahan yang tidak jelas dari hanya menggunakan stoul". Jelas itu akan mengacaukan instantiasi template, tetapi adakah hal lain yang tidak saya pertimbangkan? Komentar tentang mengapa itu ditinggalkan akan menyenangkan tetapi sekunder.
David Stone
13
@ NicolBolas Saya tidak mengerti mengapa ini tidak konstruktif. Ini adalah pertanyaan yang sangat valid karena saya tidak dapat melihat alasan apa pun untuk ketidakkonsistenan ini dan jawaban mungkin memberikan wawasan tentang beberapa alasan yang mungkin valid tetapi bukan alasan yang jelas untuk itu.
Christian Rau
4
@SethCarnegie Nah, apa yang dilakukan platform Anda (dan mungkin sebagian besar platform) tidak relevan, karena unsigned longjust is no unsigned int.
Christian Rau
4
@ SethCarnegie: di komputer biasa saya, unsigned longadalah 64 bit, dan unsigned int32. Mereka adalah tipe yang berbeda, dan tidak dapat diasumsikan sama satu sama lain.
Mike Seymour
2
@NicolBolas Seperti mengatakan, OP (dan saya) tidak tahu itu spekulatif, karena mungkin saja ada alasan valid yang sempurna untuk itu terkubur jauh di dalam bahasa internal C ++. Tapi karena Anda mengatakan itu spekulatif, saya kira tidak ada alasan seperti itu. Tapi sekali lagi, mungkin penanggung jawab C ++ 11 masih bisa menjawabnya. Ini bukanlah stoupertanyaan "Wah wah, di mana itu sialan ", tetapi pertanyaan yang menanyakan kemungkinan alasan yang pasti untuk ketidakkonsistenan yang jelas ini. Jika Anda tahu tidak ada alasan seperti itu, maka postinglah sebagai jawaban.
Christian Rau

Jawaban:

29

Jawaban yang paling tepat adalah bahwa pustaka C tidak memiliki " strtou" yang sesuai , dan fungsi string C ++ 11 semuanya terselubung tipis di sekitar fungsi pustaka C: std::sto*Fungsi cermin strto*, dan std::to_stringfungsi yang digunakan sprintf.


Sunting: Seperti yang ditunjukkan KennyTM, keduanya stoidan stoldigunakan strtolsebagai fungsi konversi yang mendasarinya, tetapi masih misterius mengapa sementara ada stoulyang menggunakan strtoul, tidak ada yang sesuai stou.

Kerrek SB
sumber
14
Tahukah Anda mengapa Komite C ++ memutuskan untuk menggunakan pendekatan C-ish seperti itu? Sesuatu boost::lexical_cast<>()sepertinya lebih seperti cara C ++ dalam melakukan sesuatu.
Paul Manta
2
Apakah detail implementasi ini benar-benar ditentukan standar?
Balapan Ringan di Orbit
4
@LightnessRacesinOrbit: For sto*, C ++ 11 21.5 / 1: Effects: dua fungsi pertama memanggil strtol (str.c_str (), ptr, base), dan tiga fungsi terakhir memanggil strtoul (str.c_str (), ptr, base ), strtoll (str.c_str (), ptr, base), dan strtoull (str.c_str (), ptr, base), masing-masing.
Mike Seymour
12
Tidak masalah apakah standar C ++ mengatakan "harus diimplementasikan dengan memanggil ...", karena standar C ++ masih memiliki aturan global as-if: jika standar mengatakan std::sto*harus diimplementasikan sebagai pembungkus untuk fungsi pustaka C, dan program yang valid tidak dapat mengatakan bahwa mereka tidak diam-diam diimplementasikan secara berbeda, implementasinya valid.
2
Benar-benar di luar topik, saya pikir alasan praktis untuk tidak menggunakan iostreams seperti yang dilakukan Boost / lexical_cast adalah kinerja semata; Saya percaya iostreams kalah melawan strtoul dll dengan selisih yang cukup besar.
Kerrek SB
22

Saya tidak tahu mengapa stoiada tetapi tidak stou, tetapi satu-satunya perbedaan antara stouldan hipotesis stouadalah pemeriksaan bahwa hasilnya berada dalam kisaran unsigned:

unsigned stou(std::string const & str, size_t * idx = 0, int base = 10) {
    unsigned long result = std::stoul(str, idx, base);
    if (result > std::numeric_limits<unsigned>::max()) {
        throw std::out_of_range("stou");
    }
    return result;
}

(Demikian pula, stoijuga mirip dengan stol, hanya dengan pemeriksaan rentang yang berbeda; tetapi karena sudah ada, tidak perlu khawatir tentang cara tepat menerapkannya.)

Mike Seymour
sumber
Perbedaan antara stoidan stol, atau stoldan stolljuga hanya merupakan pemeriksaan rentang.
Hossein
1
@Hossein: Antara stoidan stol, ya. Tapi stoldan stolltidak hanya berbeda dalam pemeriksaan jangkauan, mereka memanggil fungsi perpustakaan yang berbeda.
Ben Voigt
0
unsigned long ulval = std::stoul(buf);
unsigned long mask = ~0xffffffffl;
unsigned int uival;
if( (ulval & mask) == 0 )
    uival = (unsigned int)ulval;
else {
    ...range error...
}

Menggunakan mask untuk melakukan ini dengan ukuran nilai yang diharapkan dalam bit yang diekspresikan dalam mask, akan membuat ini berfungsi untuk int 64-bit vs 32-bit, tetapi juga untuk panjang 32-bit vs int 32-bit.

Dalam kasus panjang 64-bit, ~ 0xffffffffl akan menjadi 0xffffffff00000000 dan dengan demikian akan melihat apakah ada dari 32 bit teratas yang disetel. Dengan panjang 32-bit, ~ 0xffffffffl menjadi 0x00000000 dan pemeriksaan topeng akan selalu nol.

Gregg Wonderly
sumber