2

After learning about std::lerp I tried to use it with strong types, but it fails miserably since it only works for built in types...

#include <iostream>
#include <cmath>

struct MyFloat{

  float val = 4.7;
  MyFloat operator *(MyFloat other){
      return MyFloat(other.val*val);
  }
  MyFloat operator +(MyFloat other){
      return MyFloat(other.val+val);
  }
  MyFloat operator -(MyFloat other){
      return MyFloat(other.val-val);
  }
};
int main()
{
    MyFloat a{1}, b{10};
    //std::lerp(a, b, MyFloat{0.3}); :(
    std::lerp(a.val, b.val, 0.3f);
}

My question is: Is there a good reason why C++20 introduced a function/algorithm that is not generic?

NoSenseEtAl
  • 28,205
  • 28
  • 128
  • 277
  • The c++ dev team can only answer that authoritatevely. However I guess one can always make a type that has its own `lerp` method (by delegating for example to `std::lerp`), also it is not always possible to do linear interpolation on arbitrary types they need to be `float-like` and this cannot be enforced by templating, plus there is efficiency/size reasons to avoid clutter the `std` namespace and lib – Nikos M. Jun 30 '20 at 09:15

2 Answers2

5

It would be impossible for std::lerp to provide its guarantees about numerical behavior for arbitrary types that happen to provide some arithmetic operators. (There’s no way for the library to detect that your example merely forwards them to the builtin float versions.)

While requirements could be imposed on the parameter type to allow a correct implementation, they would need to be exceedingly detailed for MyFloat to be handled with the same performance and results as float. For example, the implementation may need to compare values of the parameter type (which your type doesn’t support!) and can capitalize on the spacing between floating-point values to provide monotonicity guarantees near t=1.

Since those guarantees are the entire point of the function (the naïve formulas are trivial), it’s not provided at all in a generic form.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76
3

Is there a good reason why C++20 introduced a function/algorithm that is not generic?

Implementing it for a small set of types makes it easier to ensure correct results when mixing different argument types and dealing with possible implicit conversions (not to mention ambiguous overloads). As the last overload on cppreference (which is likely a template) specifies, the types are adjusted such that as little precision is lost as possible.

How can the same be achieved when the list of types is open ended? And a client programmer injects whatever meaning they want into overloaded operators? I'd say its pretty much impossible.

And it's nothing new, take std::pow for instance, which had a similar overload added to it in C++11. The standard library utilities that deal with numerical data are always specified only for types the implementation is aware of.

If lerp makes sense for your custom type, then you can add overloads into your custom namespace. ADL will find it, and generic code that is build on top of

using std::lerp;
lerp(arg1, arg2, arg3);

can be made to work for your custom type too.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • I don't understand why one would say "he c++ dev team can only answer that authoritatevely." The english is rich enough to express a doubt! – Oliv Jun 30 '20 at 13:35
  • @Oliv - To be generous, rationale sometimes gets lost to the sands of time during standardization. I suppose that's what the person who posted that comment was coming from. But I don't think it should preclude us from trying to reason about implementations. S tl;dr: I don't know. – StoryTeller - Unslander Monica Jun 30 '20 at 13:38