Your question has the c++11 tag, but it's worth mentioning that std::lerp() gets you halfway there if you are compiling in c++20.
Providing your own lerp() is reasonably simple. Here's a more complete implementation of the function proposed by @Casey:
#include <cassert>
#include <type_traits>
template<typename Ta, typename Tb, typename Tt>
constexpr auto lerp(const Ta& a, const Tb& b, const Tt& t) {
static_assert(std::is_floating_point_v<Tt>);
assert(t >= Tt{0} && t <= Tt{1});
return a + t * (b - a);
}
// c++11 version:
template<typename Ta, typename Tb, typename Tt>
constexpr auto lerp(const Ta& a, const Tb& b, const Tt& t) -> decltype(a + t * (b - a)) {
static_assert(std::is_floating_point<Tt>::value, "Tt must be a floating point type");
// assert(t >= Tt{0} && t <= Tt{1}); //can't assert in constexpr code in C++11 :(
return a + t * (b - a);
}
However, lerp() doesn't quite get you where you want.
If I input 0.799999 and the range is 0 to 10, then the output should be 8.
You'd end up with a 7 since C++ rounds everything towards 0 by default. So you'll also have to manually round the value to the nearest integer. You could do this as part of the lerp, but lerp() has a fairly well defined expected behavior. Messing with that could lead to surprises.
It's better to create a seperate method for this that makes use of lerp() under the hood:
template<typename IntT, typename Tt>
constexpr IntT interpolateToNearest(const IntT& a, const IntT& b, const Tt& t) {
static_assert(std::is_integral_v<IntT>);
// There's a hidden implicit cast to IntT here.
return std::round(lerp(a, b, t));
}
// c++11 version:
template<typename IntT, typename Tt>
constexpr IntT interpolateToNearest(const IntT& a, const IntT& b, const Tt& t) {
static_assert(std::is_integral<IntT>::value, "IntT must be an integer type");
return std::round(lerp(a, b, t));
}
Note that this enforces that a, b, and the return type all be the same type. That's a bit of an arbitrary decision, and something you may or may not want to change based on your needs.
usage:
int x = interpolateToNearest(0, 10, 0.5);