7

注:これは、コンパイル時に整数型のビット数を決定するのと非常に似ていますが、これは非常に単純化されたバージョンであり、すべてが1つに含まれています。.cpp

編集:解決策を追加しました-正しい説明が与えられました(そして受け入れられました)が、私は問題を一般的に解決する方法を見つけました。

問題

問題は次のような関数にあります

 msg(int32_t);
 msg(int64_t);

のような呼び出し

long long myLong = 6;
msg(myLong);    // Won't compile on gcc (4.6.3), call is ambiguous

これはMSVCでコンパイルされます。誰かがこれが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

解決

int解決策は、longlong long適切なint32_tまたはに正常にマップする関数を提供することint64_tです。これは、実行時にif (sizeof(int)==sizeof(int32_t))typeステートメントを使用して簡単に実行できますが、コンパイル時のソリューションが推奨されます。コンパイル時のソリューションは、を使用して利用できますboost::enable_if

以下はMSVC10とgcc4.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;
}
4

2 に答える 2

3

コードがコンパイルされるかどうかは、実装によって定義されます。タイプint32_tint64_t;もありません。これらは単に、既存の整数型に対する typedef です。型がたまたま既にオーバーロードされているもの ( intlongまたはlong long) である場合 (これはほぼ確実に当てはまります)、同じ関数の複数の定義があります。それらが同じ翻訳単位にある場合は、コンパイル時エラーであり、診断が必要です。それらが異なる翻訳単位にある場合、それは未定義の動作ですが、ほとんどの実装でもエラーが発生すると思います。

あなたの場合、おそらく最善の解決策はmsg、テンプレートを作成し、型の名前を引数として渡すことです。

于 2012-05-14T08:16:11.090 に答える
3

グレッグは頭に釘を打ちます:int32_tint64_tは typedef であり、 である場合とそうでない場合がありますlong。どちらも の typedef でない場合long、オーバーロードの解決は失敗する可能性があります。long->int32_tとの両方long->int64_tがランク = 昇格 (表 12、13.3.3.1.2)

于 2012-05-14T09:42:53.283 に答える