Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to limit the template parameter to only floating point type

Is there a way to limit a template parameter T to a specific type or category?

The below code works but I want to make it simpler:

#include <iostream>
#include <type_traits>


template <typename T>
constexpr auto func( const T num ) -> T
{
    static_assert( std::is_floating_point_v<T>, "Floating point required." );

    return num * 123;
}

int main( )
{
    std::cout << func( 4345.9 ) << ' ' // should be ok
              << func( 3 ) << ' ' // should not compile
              << func( 55.0f ) << '\n'; // should be ok
}

I want to get rid of the static_assert and write something like this:

template < std::is_floating_point_v<T> >
constexpr auto func( const T num ) -> T
{
    return num * 123;
}

Any suggestions? Anything from type_traits or maybe concepts would be better.

like image 301
digito_evo Avatar asked Oct 15 '25 19:10

digito_evo


2 Answers

You can use std::floating_point concept to constrain the type T:

#include <concepts>

template<std::floating_point T>
constexpr auto func( const T num ) -> T {
  return num * 123;
}

Demo

like image 70
康桓瑋 Avatar answered Oct 17 '25 08:10

康桓瑋


The below code works but I want to make it simpler:

You may combine abbreviated function templates and the std::floating_point concept for a condensed constrained function template definition:

constexpr auto func(std::floating_point auto num) {
  return num * 123;
}

Note that this does not include an explicitly specified trailing return type T as in your original approach, but that for the current definition the deduced return type will be decltype(num), which is either float or double (or impl-defined long double). As @Barry points out in the comments below, if you require a trailing return type, say for an overload with a ref- and cv-qualified function parameter, then the brevity gain of abbreviated templates is lost to the added cost of complex trailing return type.

// Contrived example: but if this was the design intent,
// then no: skip the abbreviated function template approach.
constexpr auto func(const std::floating_point auto& num) 
  -> std::remove_cvref_t<decltype(num)> { /* ... */ }

// ... and prefer
template<std::floating_point T>
constexpr auto func(const T& num) -> T  { /* ... */ }

// ... or (preferential)
template<std::floating_point T>
constexpr T func(const T& num) { /* ... */ }
like image 31
dfrib Avatar answered Oct 17 '25 08:10

dfrib