Eu li em alguns lugares diferentes que, usando os novos literais de string do C ++ 11, pode ser possível calcular o hash de uma string em tempo de compilação. No entanto, ninguém parece estar pronto para sair e dizer que será possível ou como seria feito.
- Isso é possível?
- Qual seria a aparência da operadora?
Estou particularmente interessado em casos de uso como este.
void foo( const std::string& value )
{
switch( std::hash(value) )
{
case "one"_hash: one(); break;
case "two"_hash: two(); break;
/*many more cases*/
default: other(); break;
}
}
Observação: a função hash do tempo de compilação não precisa ser exatamente como eu a escrevi. Fiz o meu melhor para adivinhar como seria a solução final, masmeta_hash<"string"_meta>::value
também poderia ser uma solução viável.
c++
metaprogramming
c++11
hash
deft_code
fonte
fonte
Respostas:
Isso é um pouco tarde, mas consegui implementar uma função CRC32 de tempo de compilação com o uso de
constexpr
. O problema é que, no momento em que este livro foi escrito, ele só funciona com o GCC e não com o compilador MSVC ou Intel.Aqui está o snippet de código:
CrcVal01
é igual a 0x335CC04AEspero que isso ajude você!
fonte
constexpr
não está disponível no VS2013, exceto em novembro de 2013 CTP blogs.msdn.com/b/vcblog/archive/2013/11/18/…Pelo menos pela minha leitura de §7.1.5 / 3 e §5.19, o seguinte pode ser legítimo:
Isso parece seguir as regras básicas em §7.1.5 / 3:
Há alguma dúvida se os
*input
envolvem uma conversão ilegal de lvalue em rvalue, e não tenho certeza se entendi as regras em §5.19 / 2/6/2 1 e §4.1 bem o suficiente para ter certeza disso.Do ponto de vista prático, este código é aceito por (por exemplo) g ++, pelo menos desde o g ++ 4.7.1.
O uso seria algo como:
Para cumprir os requisitos de §5.19 / 2/6/2, você pode ter que fazer algo assim:
fonte
constexpr
, 2: Você não tem condição de interrupção (onde*input == nullptr
) e, pelo que entendi,constexpr
você não pode ter uma.(unsigned)-1
se houver algum; e retorna 1 para todas as outras strings. Reescrever com operador condicional ternário?Esta é uma tentativa de resolver o problema do OP da forma mais exata possível.
exemplo ao vivo .
Observe a principal diferença -
std::hash
não pode ser usado, pois não temos controle sobrestd::hash
o algoritmo de, e devemos reimplementá-lo como umconstexpr
para avaliá-lo em tempo de compilação. Além disso, não há hashes "transparentes"std
, então você não pode (sem criar umstd::string
) hash de um buffer de caractere bruto como umstd::string
.Coloquei o
std::string
hasher personalizado (comconst char*
suporte transparente ) em ummy_hash
namespace, para que você possa armazená-lo em um,std::unordered_map
se precisar de consistência.Baseado na excelente resposta de @JerryCoffin e no tópico de comentários abaixo, mas com uma tentativa de escrevê-lo com as práticas recomendadas atuais do C ++ 11 (em vez de antecipá-las!).
Observe que usar um "hash bruto" para uma
switch
instruçãocase
é perigoso. Você vai querer fazer uma==
comparação depois para confirmar se funcionou.fonte
Este trecho é baseado no de Clement JACOB. Mas também funciona com clang. E deve ser mais rápido na compilação (tem apenas uma chamada recursiva, não duas como na postagem original).
Veja a prova de conceito aqui
fonte
Observe que o formulário mostrado aqui não foi aceito no padrão, conforme observado abaixo.
Supõe-se que o processamento da string em tempo de compilação se torne possível por meio de literais definidos pelo usuário propostos no N2765 .
Como já mencionei, não conheço nenhum compilador que atualmente o implemente e sem o suporte do compilador pode haver apenas suposições.
Nos §2.13.7.3 e 4 do esboço , temos o seguinte:
Combine isso com
constexpr
e devemos ter processamento de string de tempo de compilação.update: esqueci que estava lendo o parágrafo errado, esta forma é permitida para literais inteiros definidos pelo usuário e literais-flutuantes, mas aparentemente não para literais -string (§2.13.7.5).
Esta parte da proposta parece não ter sido aceita.
Dito isso, com meu vislumbre limitado em C ++ 0x, pode ser algo assim (provavelmente eu entendi algo errado):
Se a abordagem de Jerry funcionar, o seguinte deve funcionar:
fonte
constexpr
literal definido pelo usuário. Não tenho certeza se você pode usar um literal de string como um parâmetro de modelo, eles não têm ligação estática? (eles funcionam no C ++ 98 pelo menos e, portanto, são proibidos como parâmetros de modelo).operator ""_hash
funciona para mim no Xcode 5.0.2.Outra solução baseada na de Clement JACOB, usando C ++ 11 constexpr (não o C ++ 14 estendido), mas tendo apenas uma recursão.
Alguma explicação
combine_crc32
nos permite armazenar o resultado de uma recursão em uma variávelpart
e usá-lo duas vezes. Esta função é um guia para a limitação do C ++ 11 que não permite declarações de variáveis locais.ctcrc32
função espera um literal de string, que é passado como umconst char (&)[len]
. Dessa forma, podemos obter o comprimento da string como um parâmetro de modelo e não precisamos depender de macros.fonte
O seguinte funciona no GCC 4.6.1, e você pode usar um
hash
oupack
em blocos de switch.O GCC aparentemente (?) Não permite chamadas recursivas onde passamos
s+1
coms
um ponteiro, por isso uso aoff
variável.fonte
Se você tem um compilador c ++ 17 e string_view, isso se torna trivial, basta escrever a versão normal:
fonte
crc32("mystring")
(normalmente o VS tende a fazer isso). O truque para contornar esse problema é criar uma variável constexpr que dependa da avaliação do tempo de compilação de seu crc32. Normalmenteconstexpr uint32_t val = crc32("mystring");
Aqui está outra implementação C ++ 11 (com base na resposta @ CygnusX1), que funciona com arrays constexpr char e strings de tempo de execução:
Você precisa
str.size() + 1
porquelen
na segunda sobrecarga éstrlen(str) + 1
devido ao caractere nulo no final.Não adicionei uma sobrecarga para
const char *
porque atrapalha a segunda sobrecarga - Você pode facilmente adicionar sobrecargas paraconst char *, size_t
oustd::string_view
.fonte
Esta é uma boa pergunta.
Com base na resposta de Jerry Coffin, criei outro compatível com std :: hash do Visual Studio 2017.
https://github.com/manuelgustavo/cx_hash
fonte
Eu ainda estava perdendo uma variante literal crc32 (o que não é possível com modelos), então aqui está minha sugestão com base no CygnusX1 . Fiz alguns testes, fique à vontade para dar feedback.
Testet em MSVC.
PS: Eu odeio procurar coisas adicionais em outro lugar, então copiei a tabela CRC na parte inferior da minha resposta.
Alternativa com algoritmo de Dan Bernstein (djb2) (respostas combinadas de Jerry Coffin + Georg Fritzsche )
Tabela Crc32:
fonte