This is wrong for several reasons.

# What do you mean by "is an integer"?

There are many ways to interpret the assertion that some number "is an integer". Do you mean it's an integer *type*? If so you could use the concept [`std::integral<T>`][1], but that's obviously not what you mean.

Next is checking if a given number can be stored without loss of precision in an integer *variable*. That is actually a very useful definition. However, your test would fail that because `input` might be much larger than can be stored even in a [`std::uintmax_t`][2].

Then you can check if a given number is actually exactly an integer. I am assuming that that is what you want to achieve here. Luckily that is not too hard, but see below.

Finally, it could be that you have done some floating point operations and want to know if the result is an integer, but due to the inexact nature of floating point it might not come out as an exact integer. In that case, the right tolerance to use actually depends on which and how many operations you did on the numbers before getting the final answer, as every operation increases the error. In any case:

# Don't use `epsilon`

[`epsilon`](https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon) is the smallest possible difference between floating point numbers *that are in the range of 1 to 2*. However, consider that `input` might be much larger than 1, in which case the smallest difference between `input` and `floor_input` will be much larger than `epsilon`. And if `input` is very close to 0, the opposite will be the case.

You could scale `epsilon` based on the exponent of `input`, as shown in [this example][3]. But even then it is not necessary:

# Use `std::modf()`

Due to the way the floating point number format [IEEE 754][4] works, you can tell exactly if a given `float` or `double` is an integer or not. One way would be to just cast the number to an integer and compare it with the floating point version:

```
template<typename T>
constexpr bool is_integer(T input)
{
    return static_cast<intmax_t>(input) == input;
}
```

Which works well until `input` is larger than `intmax_t` can handle. Luckily, an even better way is available by using `std::modf()`, which splits a floating point value into an integer and fractional part:

```
template<std::floating_point T>
constexpr bool is_integer(T input)
{
    T integer_part;
    return std::modf(input, &integer_part) == 0;
}

template<std::integral T>
constexpr bool is_integer(T input)
{
    return true;
}
```

This also returns `true` for `+INFINITY` and `-INFINITY`. Is infinity an integer though? On the other hand, all floating point values with an exponent larger than the size of the mantissa in bits are integers, so treating infinity as integer might be considered reasonable.

# What about other numeric types?

There are more numeric types than just integers and floating point numbers. What about [`std::complex`][5]? Maybe you are using a library that provides [rational numbers][6]? Either you could try in some way to make the code even more generic such that it handles those cases, or you could just forbid those types by requiring that [`std::is_arithmetic_v<T>`][7].

# Unnecessary use of `if`

Whenever you have a piece of code that looks like:

```
if (condition)
    return true;
else
    return false;
```

Just replace that with:

```
return condition;
```

  [1]: https://en.cppreference.com/w/cpp/concepts/integral
  [2]: https://en.cppreference.com/w/cpp/types/integer
  [3]: https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon#Example
  [4]: https://en.wikipedia.org/wiki/IEEE_754
  [5]: https://en.cppreference.com/w/cpp/numeric/complex
  [6]: https://www.boost.org/doc/libs/1_58_0/libs/rational/rational.html
  [7]: https://en.cppreference.com/w/cpp/types/is_arithmetic