具有32位/ 64位整数重载的模板函数

时间:2016-11-07 13:32:23

标签: c++ c++11 templates overloading

实际函数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还是什么?

4 个答案:

答案 0 :(得分:6)

您可以使用std::conditional仅对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);
}

答案 1 :(得分:5)

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的作业之外。

答案 2 :(得分: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

答案 3 :(得分:0)

问题是,如果您通过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 ); }