注:これは、単一.cpp
`msg(int32_t)`と `msg(int64_t)`の候補を持つ `msg(long)`のような関数のあいまいなオーバーロード
編集に:解決策を追加しました - 正しい説明が与えられた(と受理)されたが、私は一般的に問題を解決する方法を発見しました。
問題
問題が
msg(int32_t);
msg(int64_t);
のような機能を持つ。これはMSVCでコンパイル
long long myLong = 6;
msg(myLong); // Won't compile on gcc (4.6.3), call is ambiguous
ような呼び出しです。誰もgccでこれがなぜ失敗するのかについての説明を誰でも提供できます(実際にはgccが通常厳密に標準に準拠していると想定しています)。同じ効果を正しく達成する方法の例は?
#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
ソリューション
ソリューションが正常に適切なint32_t
またはint64_t
にint
、long
とlong long
をマップする機能を提供しています。これは、実行時にif (sizeof(int)==sizeof(int32_t))
タイプのステートメントを使用して簡単に行うことができますが、コンパイル時の解決策が推奨されます。コンパイル時の解決策は、boost::enable_if
を使用して入手できます。
以下は、MSVC10およびgcc 4.6.3で動作します。 非整数型を無効にすることでソリューションをさらに強化できますが、これはこの問題の範囲外です。
#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;
}
MSVCにはtypedef _Longlong int64_tがあり、gccにはtypedef long long int int64_tがあるので、両方のケースで型が同じであると思います。とにかく、それは_long_を使った呼び出しです。問題は... – Zero