patterncppMinor
Interpolating given value and legacy value from serialization buffer
Viewed 0 times
bufferserializationvalueinterpolatingandfromgivenlegacy
Problem
Here's a function that interpolates between a given value and a value fetched out of a legacy serialization buffer:
This works great for
Even if you rip out the lerp into a helper function, it still isn't ideal to repeat the function like this when the only difference from the original is the & parameter, especially if there's more than one type I'd like to pass by reference.
I can use traits to auto-detect when to use a reference:
However now the compiler can't induce the type of T by default, and the calling code has to explicitly state type:
Is there anyway to have compact calling code as well as a single defined function?
template
T interpolate(Buffer& buffer, const T currentValue, const float prop)
{
T bufferValue;
buffer.readT(&buferValue);
return currentValue + (bufferValue-currentValue)*prop;
}This works great for
interpolate and interpolate and so on. However if I want to pass a more complex structure such as a vector, I'd rather the currentValue parameter was passed by reference instead of by value. I can use overloading to handle that situation:// in addition to original function
Vector interpolate(Buffer& buffer, const Vector& currentValue, float prop)
{
Vector bufferValue;
buffer.readT(bufferValue);
return currentValue + (bufferValue-currentValue)*prop;
}Even if you rip out the lerp into a helper function, it still isn't ideal to repeat the function like this when the only difference from the original is the & parameter, especially if there's more than one type I'd like to pass by reference.
I can use traits to auto-detect when to use a reference:
// to replace original function
template
struct RefTrait { typedef const T Ref; }
template<>
struct RefTrait { typedef const Vector& Ref; }
template
T interpolate(Buffer& buffer, typename RefTrait::Ref currentValue, const float prop)
{
T bufferValue;
buffer.readT(&buferValue);
return currentValue + (bufferValue-currentValue)*prop;
}However now the compiler can't induce the type of T by default, and the calling code has to explicitly state type:
floatVal = interpolate(buffer, floatVal, 0.5f);
vectorVal = interpolate(buffer, vectorVal, 0.5f);Is there anyway to have compact calling code as well as a single defined function?
Solution
If I understand your question correctly, using the
If so then perhaps one possible idea is to create an inline wrapper function around your
It doesn't avoid the overloading but it'll at least help with the automatic type-deduction when you try to use it:
And the
But I would recommend taking a look at what Mike said first and find out really how much of a performance impact this is. If afterwards you still decide to pursue this route there are two things to keep in mind.
Edit: After thinking about my above code some more, I noticed it could be simplified a bit by just keeping the syntax the same as the OP. I've updated mines to reflect that.
RefTrait policy in your second solution is acceptable but you want to avoid specifying template parameters from the client code that's using it.If so then perhaps one possible idea is to create an inline wrapper function around your
interpolate for marshaling the call so type deduction happens automatically:template <>
struct RefTrait { typedef const Vector &Ref; };
template
T interpolateImp(Buffer& buffer, typename RefTrait::Ref currentValue, const float prop)
{
T bufferValue;
buffer.readT(&bufferValue);
return currentValue + (bufferValue-currentValue)*prop;
}
template
inline T interpolate(Buffer& buffer, T ¤tValue, const float prop)
{
return interpolateImp(buffer, currentValue, prop);
}It doesn't avoid the overloading but it'll at least help with the automatic type-deduction when you try to use it:
floatVal = interpolate(buffer, floatVal, 0.5f);
vectorVal = interpolate(buffer, vectorVal, 0.5f);And the
interpolate wrapper should get optimized away into just a interpolateImp call when the compiler inlines it.But I would recommend taking a look at what Mike said first and find out really how much of a performance impact this is. If afterwards you still decide to pursue this route there are two things to keep in mind.
- Caveat with using your current
RefTrait. At the moment,T bufferValue;in yourinterpolatecreates a locate T variable but doesn't initialize it. This poses a problem if T = const Vector&. Furthermore, it also means you're unable to change this T object later on should you need to. One possible way to fix it is to also add a valueType to your RefTraits policy. You would then usetypename T::valueTypeto create any locates you would need insideinterpolate.
- Using templates in this matter will reduce code clarity unless you're extra dilgent. The syntax has a matter of exploding in your face and could be difficult to get right especially if you're trying to cover the funny corner cases. Be sure to weight the tradeoffs.
Edit: After thinking about my above code some more, I noticed it could be simplified a bit by just keeping the syntax the same as the OP. I've updated mines to reflect that.
Code Snippets
template <>
struct RefTrait<Vector> { typedef const Vector &Ref; };
template <typename T>
T interpolateImp(Buffer& buffer, typename RefTrait<T>::Ref currentValue, const float prop)
{
T bufferValue;
buffer.readT(&bufferValue);
return currentValue + (bufferValue-currentValue)*prop;
}
template <typename T>
inline T interpolate(Buffer& buffer, T ¤tValue, const float prop)
{
return interpolateImp<T>(buffer, currentValue, prop);
}floatVal = interpolate(buffer, floatVal, 0.5f);
vectorVal = interpolate(buffer, vectorVal, 0.5f);Context
StackExchange Code Review Q#706, answer score: 5
Revisions (0)
No revisions yet.