Por que não há std :: stou?

96

C ++ 11 adicionou algumas novas funções de conversão de string:

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

Inclui stoi (string para int), stol (string para long), stoll (string para long long), stoul (string para long sem sinal), stoull (string para long long sem sinal). Notável em sua ausência é uma função stou (string para não assinado). Existe algum motivo pelo qual não é necessário, mas todos os outros são?

related: Sem funções "sto {short, unsigned short}" em C ++ 11?

David Stone
fonte
6
Minha pergunta deveria ser mais do tipo "há alguma desvantagem não óbvia de apenas usar stoul". Obviamente, isso vai bagunçar a instanciação do template, mas há mais alguma coisa que eu não estou considerando? Comentários sobre por que ele foi deixado de fora seriam bons, mas secundários.
David Stone
12
@NicolBolas Não consigo ver porque isso não é construtivo. É uma pergunta perfeitamente válida, pois não consigo ver nenhuma razão para essa inconsistência e as respostas podem fornecer insights sobre alguns motivos válidos possivelmente existentes, mas não a razão óbvia para isso.
Christian Rau
4
@SethCarnegie Bem, o que sua plataforma (e talvez a maioria das plataformas) faz é simplesmente irrelevante, porque um unsigned longsimplesmente não é unsigned int.
Christian Rau
4
@SethCarnegie: no meu computador típico, unsigned longtem 64 bits e unsigned int32. Eles são tipos diferentes e não podem ser considerados iguais.
Mike Seymour
2
@NicolBolas Como disse, o OP (e eu) não sabe que é especulativo, já que poderia haver uma razão válida perfeita para isso enterrado profundamente na linguagem interna do C ++. Mas já que você diz que é especulativo, acho que não existe esse motivo. Mas, novamente, talvez uma pessoa responsável pelo C ++ 11 ainda possa responder. Não se trata de stouuma pergunta "Wah wah, onde está essa porcaria ", mas de uma pergunta que pede uma razão possivelmente definitiva para essa inconsistência óbvia. Se você sabe que não existe esse motivo, então, poste como uma resposta.
Christian Rau

Respostas:

29

A resposta mais apropriada seria que a biblioteca C não tem “ strtou” correspondente , e as funções de string do C ++ 11 são apenas envoltórios velados em torno das funções da biblioteca C: as std::sto*funções espelham strto*e as std::to_stringfunções usam sprintf.


Edit: Como KennyTM aponta, ambos stoie stolusam strtolcomo a função de conversão subjacente, mas ainda é misterioso por que enquanto existe stoulesse usa strtoul, não há correspondente stou.

Kerrek SB
fonte
14
Você sabe por que o Comitê C ++ decidiu adotar essa abordagem C-ish? Algo como boost::lexical_cast<>()parece uma maneira mais C ++ de fazer as coisas.
Paul Manta
2
Esses detalhes de implementação são realmente definidos por padrão?
Lightness Races in Orbit
4
@LightnessRacesinOrbit: For sto*, C ++ 11 21.5 / 1: Effects: as duas primeiras funções chamam strtol (str.c_str (), ptr, base) e as três últimas funções chamam strtoul (str.c_str (), ptr, base ), strtoll (str.c_str (), ptr, base) e strtoull (str.c_str (), ptr, base), respectivamente.
Mike Seymour
12
Não importa se o padrão C ++ diz "deve ser implementado chamando ...", porque o padrão C ++ ainda tem a regra global as-if: se o padrão diz std::sto*deve ser implementado como wrappers para as funções da biblioteca C, e um programa válido não pode dizer que eles não são secretamente implementados de forma diferente, a implementação é válida.
2
Completamente fora do assunto, acho que as razões práticas para não usar iostreams como Boost / lexical_cast faz é o desempenho absoluto; Eu acredito que iostreams perde contra strtoul etc. por uma margem considerável.
Kerrek SB
22

Não tenho ideia de por que stoiexiste, mas não existe stou, mas a única diferença entre stoule um hipotético stouseria uma verificação de que o resultado está na faixa de 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;
}

(Da mesma forma, stoitambém é semelhante a stol, apenas com uma verificação de intervalo diferente; mas, uma vez que já existe, não há necessidade de se preocupar exatamente como implementá-lo.)

Mike Seymour
fonte
A diferença entre stoie stol, ou stole stolltambém é apenas uma verificação de intervalo.
Hossein
1
@Hossein: Entre stoie stol, sim. Mas stole stollnão diferem apenas na verificação de alcance, eles chamam diferentes funções de biblioteca.
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...
}

Usar máscaras para fazer isso com o tamanho do valor esperado em bits expresso na máscara fará com que funcione para longs de 64 bits vs ints de 32 bits, mas também para longs de 32 bits vs ints de 32 bits.

No caso de longos de 64 bits, ~ 0xffffffffl se tornará 0xffffffff00000000 e, portanto, verá se algum dos 32 bits principais está definido. Com longs de 32 bits, ~ 0xffffffffl torna-se 0x00000000 e a verificação da máscara sempre será zero.

Gregg Wonderly
fonte