# fmt::is_floating_point Type Trait in fmtlib: Implementation and Purpose

> Learn about fmt::is_floating_point in fmtlib. This type trait unifies standard floats and optional float128 for uniform formatting and SFINAE API design. Optimize your code.

- Repository: [Hello World Foundation/fmt](https://github.com/fmtlib/fmt)
- Tags: internals
- Published: 2026-09-09

---

**fmt::is_floating_point** is a compile-time type trait defined in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) that extends `std::is_floating_point` to recognize both standard floating-point types and the library's optional `float128` type, enabling uniform formatting and SFINAE-based API design across the fmtlib codebase.

The `fmt::is_floating_point` type trait is central to how the fmt library handles floating-point formatting consistently across platforms. Defined in the `fmtlib/fmt` repository, this trait extends the standard C++ type system to support extended precision types while maintaining compatibility with `float`, `double`, and `long double`. Understanding this utility reveals how fmtlib achieves type-safe, optimized formatting for numerical data.

## What is fmt::is_floating_point?

In [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) (around lines 869-871), the trait is implemented as a template structure that inherits from the standard `std::is_floating_point` for general use, with an explicit specialization for `float128`:

```cpp
template <typename T> struct is_floating_point : std::is_floating_point<T> {};
template <> struct is_floating_point<float128> : std::true_type {};

```

This dual approach ensures that built-in types defer to the standard library's definition, while the extended `float128` type (available when `FMT_USE_FLOAT128` is defined) is explicitly marked as a floating-point type even though `std::is_floating_point` does not recognize it.

## Purpose and Design Rationale

### Uniform Type Handling Across Formatting Functions

The primary purpose of `fmt::is_floating_point` is to provide a single, authoritative check for floating-point compatibility that works across `fmt::format`, `fmt::printf`, and chrono formatting utilities. By centralizing this definition in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h), the library ensures that precision controls, scientific notation, and other floating-point formatting features work identically for standard types and `float128`.

### SFINAE-Friendly API Constraints

The trait integrates with `FMT_ENABLE_IF` and `std::enable_if_t` to conditionally enable function overloads. This pattern appears throughout headers like [`include/fmt/printf.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/printf.h) and [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h), where the library must distinguish between integral and floating-point arguments to avoid ambiguous overloads while keeping the public API surface clean.

### Performance Optimization Gates

Internal helpers such as `is_fast_float` rely on `fmt::is_floating_point` to determine whether a type can use fast floating-point formatting paths. This compile-time check allows the library to select optimal implementation strategies in `src/format.cc` without runtime overhead.

## Practical Usage Examples

### Formatting Extended Precision Values

When `FMT_USE_FLOAT128` is enabled, you can format `float128` values using standard floating-point specifiers thanks to the trait specialization:

```cpp
#include <fmt/format.h>

#if FMT_USE_FLOAT128
int main() {
    fmt::float128 x = static_cast<fmt::float128>(3.141592653589793238462643383279502884L);
    fmt::print("pi = {:.20Lf}\n", x);  // Uses fmt::is_floating_point<float128>
}
#endif

```

### SFINAE Constraints in Custom Templates

Use the trait with `FMT_ENABLE_IF` to restrict templates to floating-point types only:

```cpp
template <typename T, fmt::enable_if_t<fmt::is_floating_point<T>::value, int> = 0>
std::string format_with_precision(T value, int prec) {
    return fmt::format("{:.{}f}", value, prec);
}

// Valid usage:
auto s1 = format_with_precision(1.23f, 2);   // float
auto s2 = format_with_precision(4.567L, 3);    // long double
#if FMT_USE_FLOAT128
auto s3 = format_with_precision(fmt::float128(9.87), 2); // float128
#endif

```

### Generic Type Processing with if constexpr

Combine the trait with C++17 `if constexpr` for type-specific logic branches:

```cpp
template <typename T>
void process_value(T v) {
    if constexpr (fmt::is_floating_point<T>::value) {
        fmt::print("Floating point: {:.6g}\n", v);
    } else {
        fmt::print("Integral: {}\n", v);
    }
}

```

## Key Source Locations

The `fmt::is_floating_point` trait and its consumers are distributed across these critical files:

- **include/fmt/format.h**: Defines the trait and its `float128` specialization
- **include/fmt/printf.h**: Uses the trait for SFINAE in `printf`-style overloads
- **include/fmt/chrono.h**: Employs the trait for floating-point duration handling
- **src/format.cc**: Implements formatting logic that branches based on floating-point classification

## Summary

- **fmt::is_floating_point** extends `std::is_floating_point` to support extended precision types, specifically `fmt::float128`, through template specialization in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h).
- The trait enables SFINAE-based template constraints via `FMT_ENABLE_IF`, preventing ambiguous overloads in `printf` and chrono formatting functions.
- It ensures uniform floating-point formatting semantics across the library, allowing `float128` to use the same precision and notation specifiers as standard types.
- Internal performance optimizations in the formatting engine use this trait to gate fast-path floating-point processing.

## Frequently Asked Questions

### What is the difference between std::is_floating_point and fmt::is_floating_point?

While `std::is_floating_point` recognizes only standard built-in floating-point types (`float`, `double`, `long double`), `fmt::is_floating_point` additionally provides a template specialization for `fmt::float128`. This allows the fmt library to treat extended precision types as first-class floating-point citizens for formatting purposes, even when the standard library does not recognize them.

### Where is fmt::is_floating_point defined in the source code?

The trait is defined in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) at approximately lines 869-871 according to the current main branch. The primary template inherits from `std::is_floating_point<T>`, while the specialization for `float128` inherits from `std::true_type` when the extended type is available.

### Can I use fmt::is_floating_point in my own code?

Yes, the trait is part of the public API and can be used for SFINAE constraints or `if constexpr` branches in generic code. Include `<fmt/format.h>` and use `fmt::is_floating_point<T>::value` to check if a type is considered a floating-point type by the fmt library.

### Does fmt::is_floating_point work with custom floating-point types?

No, `fmt::is_floating_point` specifically handles standard types and `fmt::float128`. For custom numeric types, you would need to provide your own type trait or specialize `fmt::is_floating_point` for your specific type, though the library primarily expects users to work with its built-in supported types.