Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

literals in template function for floating point types

Tags:

c++

c++11

c++14

This question has come up before, in particular here Should we generally use float literals for floats instead of the simpler double literals? but I was wondering if there were any better suggested solutions now we are in C++14 land and things like user defined literals and brace initialization exist.

The problem can be expressed as how to write a floating literal in a template function for floating point types

template <typename T> T foo( T x )
{
    static_assert( std::is_floating_point<T>::value, "" );

    T y = x * 101.0;

    return( y );
}

So the question boils down to how do we write "101.0", as it stands it's a double so what happens if I call foo using

float a = 42.0f;
float b = foo( a );

If I write "101.0f" in foo what happens if I call foo with a double, note 101.0 and 101.0f are not necessarily the same.

Also how do I guarantee that no extra code is produced to cast values?

Other suggestions include writing things like "static_cast( 101.0 )", "T( 101.0 )" or other hideous things!

like image 643
goneskiing Avatar asked Dec 11 '14 22:12

goneskiing


People also ask

What are floating-point literals?

Floating-point literals are numbers that have a decimal point or an exponential part. They can be represented as: Real literals. Binary floating-point literals. Hexadecimal floating-point literals (C only)

What is the default data type of floating-point literal?

Floating-point literals are generally double data type by default. We can assign them to float data types by adding an f at the end of the value.

How do you write a literal floating-point in Java?

The simplest form of floating point literal consists of one or more decimal digits and a decimal point ( . ) and an optional suffix ( f , F , d or D ). The optional suffix allows you to specify that the literal is a float ( f or F ) or double ( d or D ) value. The default (when no suffix is specified) is double .


2 Answers

A C++14-specific option would be to use a variable template

namespace detail
{
    template<typename F>
    F multiplier = F(101.0);
}

template <typename T> T foo( T x )
{
    static_assert( std::is_floating_point<T>::value, "" );

    T y = x * detail::multiplier<T>;

    static_assert(std::is_same<decltype(detail::multiplier<T>), T>{}, "");

    return( y );
}

Live demo

like image 151
Praetorian Avatar answered Oct 07 '22 09:10

Praetorian


template <typename T> T foo( T x ){
  static_assert( std::is_floating_point<T>::value, "" );

  T y = x * foo_constants<T>::one_o_one;

  return( y );
}

Then simply define and specialise your constants in the foo_constants struct.

You probably don't even need the static assert anymore. You could even extend your function to other algebras (vector products, matrices, quaternions, etc.).

However, it doesn't meet your terseness requirement.

like image 24
didierc Avatar answered Oct 07 '22 09:10

didierc