Determinar o número de bits no tipo integral em tempo de compilação
NOTA: Eu adicionei uma versão semelhante mas muito simplificada do problema emSobrecarga ambígua de funções como `msg (long)` com candidatos `msg (int32_t)` e `msg (int64_t)`. Essa versão tem a vantagem de um exemplo compilável completo em um único arquivo.
ProblemaEu tenho uma biblioteca C com funções como
<code>obj_from_int32(int32_t& i); obj_from_int64(int64_t& i); obj_from_uint32(uint32_t& i); obj_from_uint64(uint64_t& i); </code>
Neste caso, os tiposint32_t
etc sãonão astd
ones - são implementação definida, neste caso uma matriz de chars (no exemplo a seguir omiti a conversão - ela não altera a questão que é sobre o mapeamento de tipos intergral para uma função específica baseada no número de bits em o tipo integral).
Eu tenho uma segunda classe de interface C ++, que tem construtores como
<code>MyClass(int z); MyClass(long z); MyClass(long long z); MyClass(unsigned int z); MyClass(unsigned long z); MyClass(unsigned long long z); </code>
Note que não posso substituir esta interface porstd::int32_t
tipos de estilo - se eu pudesse, não precisaria fazer essa pergunta;)
O problema é como chamar o corretoobj_from_
função baseada no número de bits no tipo integral.
Estou colocando duas soluções propostas, já que nenhuma solução matadora chegou ao topo da lista, e há algumas que estão quebradas.
Solução 1Fornecido porCheers e hth. - Alf. Comentários deste ponto em diante são meus - sinta-se livre para comentar e / ou editar.
Vantagens - Razoavelmente simples (pelo menos em comparação comboost::enable_if
) - Não depende da biblioteca de terceiros (desde que o compilador suportetr1
)
* Desvantagens ** - Se mais funções (comoanotherObj_from_int32
etc) são necessários, muito mais código é necessário
Esta solução pode ser encontrada abaixo - dê uma olhada, é bacana!
Solução 2Vantagens
Uma vez oConvertFromIntegral
funções são feitas, adicionando novas funções que precisam da conversão é trivial - basta escrever um conjunto sobrecarregado emint32_t
, int64_t
e equivalentes não assinados.
Mantém o uso de modelos em um único local, eles não se espalham à medida que a técnica é reutilizada.
Desvantagens
Pode ser excessivamente complicado, usandoboost::enable_if
. Algo atenuado pelo fato de isso aparecer em apenas um lugar.Como isso é meu, não posso aceitá-lo, mas você pode fazer o upvote se achar que é legal (e claramente algumas pessoas o fazem).não acho que é legal em tudo, é para isso que eu acho que é downvote!) Obrigado a todos que contribuíram com ideias!
A solução envolve uma função de conversãoint
, long
elong long
paraint32_t
eint64_t
(e similar para as versões não assinadas). Isso é combinado com outro conjunto de funções sobrecarregadasint32_t
, int64_t
e equivalentes não assinados. As duas funções podem ser combinadas, mas as primeiras funções de conversão tornam um útil conjunto de utilitários que pode ser reutilizado e, em seguida, o segundo conjunto de funções é trivialmente simples.
<code>// Utility conversion functions (reuse wherever needed) template <class InputT> typename boost::enable_if_c<sizeof(InputT)==sizeof(int32_t) && boost::is_signed<InputT>::value, int32_t>::type ConvertFromIntegral(InputT z) { return static_cast<int32_t>(z); } template <class InputT> typename boost::enable_if_c<sizeof(InputT)==sizeof(int64_t) && boost::is_signed<InputT>::value, int64_t>::type ConvertFromIntegral(InputT z) { return static_cast<int64_t>(z); } template <class InputT> typename boost::enable_if_c<sizeof(InputT)==sizeof(uint32_t) && boost::is_unsigned<InputT>::value, uint32_t>::type ConvertFromIntegral(InputT z) { return static_cast<uint32_t>(z); } template <class InputT> typename boost::enable_if_c<sizeof(InputT)==sizeof(uint64_t) && boost::is_unsigned<InputT>::value, uint64_t>::type ConvertFromIntegral(InputT z) { return static_cast<uint64_t>(z); } // Overload set (mock implementation, depends on required return type etc) void* objFromInt32 (int32_t i) { obj_from_int32(i); } void* objFromInt64 (int64_t& i) { obj_from_int64(i); } void* objFromUInt32(uint32_t& i) { obj_from_uint32(i); } void* objFromUInt64(uint64_t& i) { obj_from_uint64(i); } // Interface Implementation MyClass(int z) : _val(objFromInt(ConvertFromIntegral(z))) {} MyClass(long z): _val(objFromInt(ConvertFromIntegral(z))) {} MyClass(long long z): _val(objFromInt(ConvertFromIntegral(z))) {} MyClass(unsigned int z): _val(objFromInt(ConvertFromIntegral(z))) {} MyClass(unsigned long z): _val(objFromInt(ConvertFromIntegral(z))) {} MyClass(unsigned long long z): _val(objFromInt(ConvertFromIntegral(z))) {} </code>
Um simplificado (único compilável.cpp
!) versão da solução é dada emSobrecarga ambígua de funções como `msg (long)` com candidatos `msg (int32_t)` e `msg (int64_t)`