Niejednoznaczne przeciążenie funkcji, takich jak `msg (długi)` z kandydatami `msg (int32_t)` i `msg (int64_t)`
Uwaga: Jest to bardzo podobne doOkreśl liczbę bitów w typie integralnym w czasie kompilacji, jednak jest to wersja znacznie uproszczona, wszystkie zawarte w jednym.cpp
Edytować: Dodano rozwiązanie - chociaż poprawnewyjaśnienie został podany (i zaakceptowany) Znalazłem sposób na rozwiązanie problemu w sposób ogólny.
ProblemProblem dotyczy funkcji takich jak
<code> msg(int32_t); msg(int64_t); </code>
połączenie jak
<code>long long myLong = 6; msg(myLong); // Won't compile on gcc (4.6.3), call is ambiguous </code>
To kompiluje na MSVC. Czy ktoś może wyjaśnić, dlaczego to się nie powiedzie na gcc (zakładam, że prawdopodobnie ma to związek z faktem, że gcc jest zwykle ściśle zgodne ze standardami) i przykładem, jak poprawnie osiągnąć ten sam efekt?
<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>Rozwiązanie
Rozwiązaniem jest funkcja, która z powodzeniem mapujeint
, long
ilong long
do właściwegoint32_t
lubint64_t
. Można to zrobić trywialnie w czasie wykonywania przezif (sizeof(int)==sizeof(int32_t))
instrukcje typu, ale rozwiązanie do kompilacji jest preferowane. Rozwiązanie do kompilacji jest dostępne poprzez użycieboost::enable_if
.
Poniższe prace dotyczą MSVC10 i gcc 4.6.3. Rozwiązanie może być dodatkowo wzmocnione przez wyłączenie dla typów nieintegralnych, ale to wykracza poza zakres tego problemu.
<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>