7

注: 「msg(int32_t)」および「msg(int64_t)」の候補を使用した「msg(long)」のような関数のあいまいなオーバーロードで、同様の、しかし大幅に簡略化されたバージョンの問題を追加しました。このバージョンには、1 つのファイルに完全にコンパイル可能な例があるという利点があります。

問題

次のような関数を備えたCライブラリがあります

obj_from_int32(int32_t& i);
obj_from_int64(int64_t& i);
obj_from_uint32(uint32_t& i);
obj_from_uint64(uint64_t& i);

この場合、型int32_tなどは型ではありませんstd- これらは実装定義であり、この場合は char の配列です (次の例では変換を省略しています - 整数型を型にマッピングすることに関する質問は変わりません)整数型のビット数に基づく特定の関数)。

次のようなコンストラクタを持つ2番目のC++インターフェイスクラスがあります

MyClass(int z);
MyClass(long z);
MyClass(long long z);
MyClass(unsigned int z);
MyClass(unsigned long z);
MyClass(unsigned long long z);

このインターフェイスをstd::int32_tスタイル タイプに置き換えることはできないことに注意してください。できれば、この質問をする必要はありません ;)

obj_from_問題は、整数型のビット数に基づいて正しい関数を呼び出す方法です。

提案されたソリューション

リストの一番上に浮かんでいるキラーソリューションはなく、壊れているものもいくつかあるため、2つの提案されたソリューションを掲載しています。

解決策 1

Cheers および hth提供。- アルフ。この時点からのコメントは私自身のものです。自由にコメントおよび/または編集してください。

利点 - かなりシンプル (少なくとも に比べてboost::enable_if) - サードパーティのライブラリに依存しない (コンパイラがサポートしている限りtr1)

*短所** - より多くの関数 (anotherObj_from_int32など) が必要な場合は、さらに多くのコードが必要になります。

この解決策は以下にあります - 見てください。

解決策 2

利点

  • 関数が完成したら、ConvertFromIntegral変換が必要な新しい関数を追加するのは簡単です - オーバーロードされたセットと符号なしの等価物を書くだけint32_tですint64_t

  • テンプレートの使用は 1 か所のみにとどめます。テクニックが再利用されるため、テンプレートは広がりません。

短所

  • を使用すると、非常に複雑になる可能性がありますboost::enable_if。これが 1 か所にしか表示されないという事実によって、いくらか軽減されます。

これは私自身のものなので、私はそれを受け入れることはできませんが、それがきちんとしていると思うなら、賛成票を投じることができます(明らかに、まったくきちんとしているとは思わない人もいます。それが反対票を投じるものだと思います!)アイデアを投稿しました!

int解決策には、からlongおよびlong longint32_tの変換関数が含まれますint64_t(署名なしバージョンについても同様です)。int32_tこれは、でオーバーロードされた別の関数セットint64_tおよび符号なしの等価物と組み合わされます。2 つの関数を組み合わせることができますが、最初の変換関数は再利用できる便利なユーティリティ セットを作成し、2 番目の関数セットは自明のことです。

// 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))) {}

ソリューションの単純化された (単一のコンパイル可能.cpp!) バージョンは、候補 `msg(int32_t)` および `msg(int64_t)` を持つ `msg(long)` のような関数のあいまいなオーバーロードで提供されます。

4

5 に答える 5

3

サードパーティ機能を考えると…

void obj_from_int32( int32_bytes_t& i );
void obj_from_int64( int64_bytes_t& i );
void obj_from_uint32( uint32_bytes_t& i );
void obj_from_uint64( uint64_bytes_t& i );

次のように、組み込み型に対して「正しい」そのような関数を呼び出すことができます。

template< int nBytes, bool isSigned >
struct ThirdParty;

template<>
struct ThirdParty< 4, true >
{
    template< class IntegralT >
    static void func( IntegralT& v )
    { obj_from_int32( v ) }    // Add whatever conversion is required.
};

// Etc., specializations of ThirdParty for unsigned and for 8 bytes.

template< class IntegralT >
void myFunc( IntegralT& v )
{ ThirdParty< sizeof( v ), std::is_signed< IntegralT >::value >::func( v ); }
于 2012-05-15T02:25:29.207 に答える
2

リンクされた問題で発見したように、ここでは long があいまいさの原因です。この線

MyClass(long z): _val(objFromInt(z)) {}

次のように変更する必要があります。

MyClass(long z): _val(sizeof(long) == 4 ? static_cast<int32_t>(z) : static_cast<int64_t>(z)))) {}

おそらく、64 ビット gcc の long long で同様の問題に直面することに注意してください。

于 2012-05-14T09:02:11.370 に答える
1

他の回答で指摘されているように、これは実行時にif(sizeof(int)==sizeof(int32_t))スタイルブランチを使用して簡単に解決できます。コンパイル時にこれを行うには、 boost::enable_ifを使用できます。

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); }

整数型を、、に変換する必要がある場合はどこでもint32_tint64_tまたはuint32_t単にuint64_t次のように呼び出す必要があります。

ConvertIntegral(long(5));  // Will return a type compatible with int32_t or int64_t

この機能は、完全なソリューションのために設定された過負荷とConvertIntegral組み合わせることができます。あるいは、示されている手法を過負荷セットに組み込むこともできます。int32_tint64_t

また、非整数​​型を無効にすることで、上記をさらに強化することもできます。関数の使用の完全な例については、「msg(long)」のような関数と候補「msg(int32_t)」および「msg(int64_t)」のあいまいなオーバーロードを参照してください。

于 2012-05-15T00:57:35.373 に答える
0

あいまいさは、符号付きと符号なしの両方の型のオーバーロードから簡単に発生する可能性があります。たとえば、与えられた

void foo(unsigned int);
void foo(long);

thenは両方からfoo(0)のコンバージョン (またはプロモーション) としてあいまいで、ランク付けは同じです。intunsigned intlong

署名されていない型を使用するコンストラクターのオーバーロードを使用している場合 (およびそれを気にしている場合) は、1 つの署名を選択するか、各署名に対して 2 つのオーバーロード セットを記述します。

于 2012-05-14T06:49:54.487 に答える