Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template function with 32-bit/64-bit integer overloads

The actual function bar is supposed to read from file, where data is written in exactly 4 bytes or 8 bytes (unsigned int - DWORD or 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
}

Since the caller can pass any integer type (int, LONG, DWORD, LONGLONG or anything) - I want a technique so that foo may make a call to 32-bit bar or 64-bit bar.

In short, it would be like:

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

Obviously, I want the "if" part to be resolved at compile time. std::enable_if or something?

like image 999
Ajay Avatar asked Dec 03 '25 13:12

Ajay


2 Answers

Soltuion 1: SFINAE and 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: Delegate-to-class and partial specialisation:

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

Both solutions can be flavoured with static_cast added to taste, particularly around assignment to/from arg.

like image 141
Angew is no longer proud of SO Avatar answered Dec 05 '25 01:12

Angew is no longer proud of SO


You could use std::conditional to only differ for sizeof(DWORD) and sizeof(DWORD64) (since you want to support more than just those 2 types):

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);
}
like image 29
Hatted Rooster Avatar answered Dec 05 '25 02:12

Hatted Rooster



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!