Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to express a templated numeric literal?

I have a function that could be reduced to something like this:

template<class T>
T foo(T x)
{
  return 123.45 / x;
}

I would like to ensure that the numeric literal 123.45 is the same type as x. Let's say that T could be any numeric type: signed/unsigned char to long-long or float to long-double.

What is the most modern way to indicate that 123.45 should be of type T?

My requirements

  • No warnings should be emitted (with every warning turned on).
  • I want the decimal number 123.45 to have the precision of T when used in the calculation.
  • I want the most elegant solution that achieves these goals.

Issues under consideration

  • The “old-style cast”, i.e. (T)123.45 is essentially deprecated in C++.
  • static_cast<T>(123.45) seems like the right type of cast. However, it is verbose, and I have never seen this used on a literal.
  • I am unsure if a suffix (e.g. 123.45L) is necessary in order to get the maximum precision in the case of T being long double, or if the compiler will automatically use the highest precision decimal-to-binary conversion.

Update 5-7-2014

After changing hundreds of casts in my codebase to the form T(123.45), I found that there are times when this syntax is unavailable. For example, you can not do long double(123.45) because C++ does not support multitoken type constructors. In these cases, I have opted for static_cast<long double>(123.45).

like image 775
user4938472 Avatar asked Oct 22 '25 22:10

user4938472


2 Answers

What about a simple

template<class T>
T foo(T x)
{
  return T(123.45) / x;
}

which will allow custom numeric classes to accept the value in a constructor.

static_cast is the way to go. This is what the C cast is equivalent to, in any cast that preserves the original meaning but changes the type of the value.

If it's a class type with numeric features, static_cast will call a one-argument constructor, even an explicit one.

If you want to avoid narrowing conversions, you can use the syntax T{ 123.45 }. This is not like a C-style cast, but uses direct-list-initialization. It still allows an explicit constructor, but any numeric conversion to its parameter type must be exact. (No overflow or rounding allowed. For literals, this constraint is checked for the particular value, not as a relationship between types. However, GCC warns when I pass 12.0 to an int; I'm not sure if that's right or not.)

like image 40
Potatoswatter Avatar answered Oct 25 '25 11:10

Potatoswatter