Sobrecarga ambígua de funções como `msg (long)` com candidatos `msg (int32_t)` e `msg (int64_t)`
Nota: Isso é muito parecido comDeterminar o número de bits no tipo integral em tempo de compilação, no entanto, esta é uma versão muito simplificada, tudo contido em um único.cpp
Editar: Adicionado uma solução - embora um corretoexplicação foi dado (e aceite) eu encontrei uma maneira de resolver o problema genericamente.
ProblemaO problema é com funções como
<code> msg(int32_t); msg(int64_t); </code>
uma chamada como
<code>long long myLong = 6; msg(myLong); // Won't compile on gcc (4.6.3), call is ambiguous </code>
Isso compila no MSVC. Alguém pode fornecer uma explicação de por que isso falha no gcc (eu estou supondo que provavelmente está relacionado ao fato de o gcc ser geralmente estritamente compatível com os padrões) e um exemplo de como obter corretamente o mesmo efeito?
<code>#include <iostream> #include <stdint.h> #include <boost/integer.hpp> using namespace std; void msg(int v) { cout << "int: " << sizeof(int) << ' ' << v << '\n'; } void msg(long v) { cout << "long: " << sizeof(long) << ' ' << v << '\n'; } void msg(long long v) { cout << "long long: " << sizeof(long long) << ' ' << v << '\n'; } void msg2(int32_t v) { cout << "int32_t: " << sizeof(int32_t) << ' ' << v << '\n'; } void msg2(int64_t v) { cout << "int64_t: " << sizeof(int64_t) << ' ' << v << '\n'; } void msg2(uint32_t v) { cout << "uint32_t: " << sizeof(uint32_t) << ' ' << v << '\n'; } void msg2(uint64_t v) { cout << "uint64_t: " << sizeof(uint64_t) << ' ' << v << '\n'; } int main() { int myInt = -5; long myLong = -6L; long long myLongLong = -7LL; unsigned int myUInt = 5; unsigned int myULong = 6L; unsigned long long myULongLong = 7LL; msg(myInt); msg(myLong); msg(myLongLong); msg2(myInt); msg2(myLong); // fails on gcc 4.6.3 (32 bit) msg2(myLongLong); msg2(myUInt); msg2(myULong); // fails on gcc 4.6.3 (32 bit) msg2(myULongLong); return 0; } // Output from MSVC (and gcc if you omit lines that would be commented out) int: 4 5 long: 4 6 long long: 8 7 int32_t: 4 -5 int32_t: 4 -6 // omitted on gcc int64_t: 8 -7 uint32_t: 4 5 uint32_t: 4 6 // omitted on gcc uint64_t: 8 7 </code>Solução
A solução é fornecer uma função que mapeia com sucessoint
, long
elong long
para o apropriadoint32_t
ouint64_t
. Isso pode ser feito trivialmente em tempo de execução viaif (sizeof(int)==sizeof(int32_t))
tipo declarações, mas uma solução em tempo de compilação é preferível. Uma solução em tempo de compilação está disponível através do uso deboost::enable_if
.
O seguinte funciona no MSVC10 e gcc 4.6.3. A solução poderia ser aprimorada com a desativação de tipos não integrais, mas isso está fora do escopo desse problema.
<code>#include <iostream> #include <stdint.h> #include <boost/integer.hpp> #include <boost/utility/enable_if.hpp> #include <boost/type_traits/is_signed.hpp> #include <boost/type_traits/is_unsigned.hpp> using namespace std; template <class InputT> typename boost::enable_if_c<sizeof(InputT)==sizeof(int32_t) && boost::is_signed<InputT>::value, int32_t>::type ConvertIntegral(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 ConvertIntegral(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 ConvertIntegral(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 ConvertIntegral(InputT z) { return static_cast<uint64_t>(z); } void msg(int v) { cout << "int: " << sizeof(int) << ' ' << v << '\n'; } void msg(long v) { cout << "long: " << sizeof(long) << ' ' << v << '\n'; } void msg(long long v) { cout << "long long: " << sizeof(long long) << ' ' << v << '\n'; } void msg2(int32_t v) { cout << "int32_t: " << sizeof(int32_t) << ' ' << v << '\n'; } void msg2(int64_t v) { cout << "int64_t: " << sizeof(int64_t) << ' ' << v << '\n'; } void msg2(uint32_t v) { cout << "uint32_t: " << sizeof(uint32_t) << ' ' << v << '\n'; } void msg2(uint64_t v) { cout << "uint64_t: " << sizeof(uint64_t) << ' ' << v << '\n'; } int main() { int myInt = -5; long myLong = -6L; long long myLongLong = -7LL; unsigned int myUInt = 5; unsigned int myULong = 6L; unsigned long long myULongLong = 7LL; msg(myInt); msg(myLong); msg(myLongLong); msg2(ConvertIntegral(myInt)); msg2(ConvertIntegral(myLong)); msg2(ConvertIntegral(myLongLong)); msg2(ConvertIntegral(myUInt)); msg2(ConvertIntegral(myULong)); msg2(ConvertIntegral(myULongLong)); return 0; } </code>