2016-11-07 8 views
2

実際の機能barは、データが正確に4バイトまたは8つのバイトに書き込まれるファイル、(unsigned intからDWORD又はDWORD64)から読み出すことになっているオーバーロードテンプレート関数は

void bar(DWORD64&); 
void bar(DWORD&); 

template<typename IntType> 
void foo(IntType& out) 
{ 
    bar(out); 
} 

int main() 
{ 
    int a; 
    foo(a); // Caller doesn't care 
} 

呼び出し側は、任意の整数型(intLONGDWORDLONGLONGまたは何か)を渡すことができるので - 私は技術を必要foo 32ビットbarまたは64ビットbarに電話をかけることができるようになっています。要するに

、それは次のように次のようになります。

明らか
template<typename IntType> 
void foo(IntType& out) 
{ 
     if(sizeof(out)==sizeof(DWORD)) // 32-bit 
     { 
      DWORD data; 
      bar(data); // call DWORD version 
      out = (IntType)data; // Ignore truncation etc. 
     } 
     else 
     { 
      DWORD64 data; 
      bar(data); // call DWORD64 version 
      out = (IntType)data; // Ignore truncation etc. 
     } 
} 

、私はコンパイル時に解決される「場合」の部分をしたいです。 std::enable_ifまたは何か?

+1

代わりに*専門化*を使用してください。 –

+0

あなたはsfinaeを考えましたか? –

+0

@ W.F。はい、私はSFINAEを考えましたが、動作させることはできません。 – Ajay

答えて

6

template<typename IntType> 
void foo(IntType& out) 
{ 
    typedef typename std::conditional<sizeof(IntType) == sizeof(DWORD), DWORD, DWORD64>::type RetType; 
    RetType data; 
    bar(data); 
    out = static_cast<IntType>(data); 
} 
+0

偉大な答えをありがとう。私にとって、32ビット以下の整数はすべてDWORDです。すべての64ビット整数はDWORD64です。ですから、 '=='を '<='で置き換えるだけです。 – Ajay

4

あなたはタイプを選択しstd::conditionalを使用することができます。

template<typename IntType> 
void foo(IntType& out){ 
    using dword_t = typename std::conditional<sizeof(IntType) == sizeof(DWORD), DWORD, DWORD64>::type; 
    dword_t data; 
    bar(data); 
    out = (IntType)data; 
} 

demo


はC++ 17あなたはconstexpr ifを使用することができますが、是非、このアプローチは、実際にはもっとある場合、私はわからないんだけど可読性:

template<typename IntType> 
void foo(IntType& out) 
{ 
     if constexpr(sizeof(out)==sizeof(DWORD)) // 32-bit 
     { 
      DWORD data; 
      bar(data); // call DWORD version 
      out = (IntType)data; // Ignore truncation etc. 
     } 
     else 
     { 
      DWORD64 data; 
      bar(data); // call DWORD64 version 
      out = (IntType)data; // Ignore truncation etc. 
     } 
} 

demo

ユーザーは、(あなただけのものを2種類以上のものをサポートしたいので) sizeof(DWORD)sizeof(DWORD64)のために異なるに std::conditionalを使用することができ
0

質問あなたはint16_tを渡された場合、あなたがしたいんさ符号拡張、ゼロフィル、またはエラー?

template <typename IntType> 
void foo (IntType * out) = delete; 

template <> 
void foo (uint64_t * out) { bar (* (DWORD64 *) out); } 

template <> 
void foo (int64_t * out) { bar (* (DWORD64 *) out); } 

template <> 
void foo (uint32_t * out) { bar (* (DWORD *) out); } 

template <> 
void foo (int32_t * out) { bar (* (DWORD *) out); } 
+2

しかし、それはOPが望むものではありません。彼らはすべてを受け入れるが、適切な大きさの 'bar'のオーバーロードを呼び出させたい。 – Angew

+0

@Angew OK、適切なサイズの符号付き整数に対してオーバーロードを追加しました。しかし、他の過負荷を有効にすることは単に無責任です。 OPの元のコードでは、uint16_tはuint64_tに昇格されると言われていますが、彼は問題の説明でそれを言っていないので間違っている可能性があります。 – KevinZ

+0

@ user2079303 uint16を使用した場合、4つの特殊化すべてに対する置換の失敗は実際にはエラーではありません。特殊化されていないフォームに対する代入もエラーではありません。このエラーは、 '= delete'によって強制されます。 – KevinZ

5

Soltuion 1:行うには

IMO正しい事はそうここに、テンプレート特殊とソリューションのエラーでSFINAEとstd::enable_if

template<typename IntType, typename std::enable_if<sizeof(IntType) == 4>::type* = nullptr> 
void foo(IntType& out) 
{ 
    DWORD arg = out; 
    bar(arg); 
    out = arg; 
} 

template<typename IntType, typename std::enable_if<sizeof(IntType) == 8>::type* = nullptr> 
void foo(IntType& out) 
{ 
    DWORD64 arg = out; 
    bar(arg); 
    out = arg; 
} 

Soltuion 2:委任ツークラス部分的な専門化:

template<typename IntType> 
void foo(IntType& out) 
{ 
    foo_helper<IntType>::call(out); 
} 

template <class IntType, std::size_t Size = sizeof(IntType)> 
struct foo_helper; 

template <class IntType> 
struct foo_helper<IntType, 4> 
{ 
    static void call(IntType &out) 
    { 
    DWORD arg = out; 
    bar(arg); 
    out = arg; 
    } 
}; 

template <class IntType> 
struct foo_helper<IntType, 8> 
{ 
    static void call(IntType &out) 
    { 
    DWORD64 arg = out; 
    bar(arg); 
    out = arg; 
    } 
}; 

両方の溶液を特にargへの/からの割り当ての周りに、static_castが追加されました。

関連する問題