0

Is there any way, to default second template type to the type of the first template argument type, to remove the need of specifying the template types when not needed?

So, I have a method, that pops values from byte array:

    template<class TYPE1, class TYPE2>
    bool pop_value_from_array(TYPE2 &value)
    {
        if(get_array_size() >= sizeof(TYPE1))
        {
            value = static_cast<TYPE2>(*reinterpret_cast<const TYPE1*>(get_array_pointer()));
            remove_bytes_from_array(sizeof(TYPE1));
            return true;
        }
        return false;
    }

And then I can do

    uint32_t size;
    if (!pop_value_from_array<uint16_t>(size))
    {
        // Error handling
    }
    size *= 2;
    uint16_t var2;
    if (!pop_value_from_array<uint16_t>(var2))
    {
        // Error handling
    }

If I declare another function:

    template<class TYPE>
    bool pop_value_from_array(TYPE &value)
    {
        if(get_array_size() >= sizeof(TYPE))
        {
            value = *reinterpret_cast<const TYPE*>(get_array_pointer());
            remove_bytes_from_array(sizeof(TYPE));
            return true;
        }
        return false;
    }

I can get rid of the template specification when not needed:

    uint32_t size;
    // Poping uint16_t from array, and storing to the uint32_t type, so there is no overflow in multiplication
    if (!pop_value_from_array<uint16_t>(size))
    {
        // Error handling
    }
    size *= 2;
    uint16_t var2;
    if (!pop_value_from_array(var2))
    {
        // Error handling
    }

So, I want to get rid of the second declaration of the same function

  • Are these member functions of a class? including `get_array_pointer` / `get_array_size`? It really looks like `TYPE1` should be a known to the class, and then `pop_value_from_array` would only have one template parameter. Otherwise your example has undefined behaviour – Caleth May 10 '23 at 11:52
  • So basically this function can be explained as: if there is enough bytes in array, interpret bytes from array as TYPE1, and static cast it to a TYPE2, and then shift the array pointer – Alexander Labuuu May 10 '23 at 12:09
  • If the array is not an array of `TYPE1`, then that has undefined behaviour. If it is, why have you type-erased `TYPE1`? You need to `memcpy` into an actual `TYPE1` object to interpret those bytes as a `TYPE1` – Caleth May 10 '23 at 12:12
  • Array is just array of bytes – Alexander Labuuu May 10 '23 at 13:26
  • Yes, so there isn't a `TYPE1` for you to dereference – Caleth May 10 '23 at 13:41
  • @Caleth No, the TYPE1 is used to interpret the array of bytes (int16 for example), and static casted to int32 for example – Alexander Labuuu May 10 '23 at 18:35
  • That's what I'm saying. It is undefined behaviour to `reinterpret_cast` your bytes – Caleth May 11 '23 at 08:37
  • Why is that undefined behavior? – Alexander Labuuu May 12 '23 at 09:41
  • Sorry, dereferencing that pointer is undefined behaviour, because `reinterpret_cast` is very specific as to what types you can convert between. You can't magic a `TYPE1` out of bytes, unless `TYPE1` is either `char`, `unsigned char` or `std::byte` – Caleth May 12 '23 at 09:45

2 Answers2

0

Templates parameters can be defaulted:

    template<class TYPE1, class TYPE2=TYPE1>
    bool pop_value_from_array(TYPE2 &value)
// ...

Now this template can be invoked with just one parameter, and the second one gets defaulted in the expected manner.

There are some restrictions on template parameter defaulting. Your C++ textbook should have the complete details.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
0

You might default TYPE1 to some special type (I use void here), and then check for that type:

template<class TYPE1 = void, class TYPE2>
bool pop_value_from_array(TYPE2 &value)
{
    using type = std::conditional_t<std::is_same_v<void, TYPE1>, TYPE2, TYPE1>;
    // Now use type.
    if(get_array_size() >= sizeof(type))
    {
        value = static_cast<TYPE2>(*reinterpret_cast<const type*>(get_array_pointer()));
        remove_bytes_from_array(sizeof(type));
        return true;
    }
    return false;
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302