簡體   English   中英

具有32位/ 64位整數重載的模板函數

[英]Template function with 32-bit/64-bit integer overloads

實際的功能bar應該從文件中讀取,其中數據以4字節或8字節的形式寫入( unsigned int - DWORDDWORD64

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.
       }
 }

顯然,我希望在編譯時解決“ if ”部分。 std::enable_if還是什么?

你可以使用std::conditionalsizeof(DWORD64) sizeof(DWORD)sizeof(DWORD64) (因為你不僅僅支持這兩種類型):

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

Soltuion 1: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;
  }
};

這兩種解決方案都可以通過添加static_cast進行調味,特別是在arg分配時。

您可以使用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;
}

演示


來吧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.
       }
 }

演示

問題是,如果你傳遞了一個int16_t ,你想簽名擴展,零填充還是錯誤?

IMO正確的做法是錯誤,所以這里有一個模板特化的解決方案:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM