0

Say I have a simple function that does something like this:

template<typename T>
T get_half(T a){
    return 0.5*a;
}

this function will typically be evaluated with T being double or float. The standard specifies that 0.5 will be a double (0.5f for float). How can write the above code so that 0.5 will always be of type T so that there is no cast when evaluating either the product or the return? What I want is 0.5 to be a constant of type T at compile time. The point of this question is that I want to avoid conversion at run time.

For example, if I write:

template<typename T>
T get_half(T a){
    return T(0.5)*a;
}

Can I be absolutely sure that T(0.5) is evaluated at compile time? if not, what would be the proper approach to accomplish this? I'm ok with using c++11 if that is needed.

Thank you in advance.

In c++11 I have a numeric_traits class something as follows (within a header file)

template<typename Scalar>
struct numeric_traits{
    static constexpr Scalar one_half = 0.5;
    //Many other useful constants ....
};

so within my code I would use this as:

template<typename T>
T get_half(T a){
    return numeric_traits<T>::one_half*a;
}

This does what I want i.e. 0.5 is resolved at compile time with the precision I need and no casts happen at run-time. However the downsides are:

  • I need to modify numeric_traits every time I need a new constant
  • The sintax is probably too verbosely annoying? (not a big issue really, of course)
  • It'd be nice maybe have something like: constant(0.5) which resolves to T type at run-time.

Thank you in advance again.

Alejandro
  • 1,064
  • 1
  • 8
  • 22
  • IIRC an explicit conversion applied to a literal is considered a `constexpr`, so yes, it's evaluated at compile time. – The Paramagnetic Croissant Feb 07 '15 at 17:17
  • 1
    @TheParamagneticCroissant Something that's valid in a constant expression may still be evaluated at run time. There are fewer scenarios where expressions are *required* to be evaluated at compile time than you might think. –  Feb 07 '15 at 17:24
  • @TheParamagneticCroissant than you for your comment. It'd be nice to have your feedback regarding my edit. – Alejandro Feb 10 '15 at 14:39
  • @hvd thank you again for your interest. Maybe my new edit would clarify? – Alejandro Feb 10 '15 at 14:40

1 Answers1

2

There isn't and cannot be any way of forcing constants to never be computed at run-time, because some machines simply don't have a single instruction that can load all possible values of a type. For instance, machines may only have a 16-bit load constant instruction, where 0x12345678 would need to be computed, at run-time, as 0x1234 << 16 | 0x5678. Alternatively, such a constant might be loaded from memory, but that could be an even more costly operation than computing it.

You need to trust your compiler a little bit. On systems where it is feasible, any compiler that has any amount of optimisation at all will translate T(0.5) the same way it will translate 0.5f, assuming T is float. And 0.5f will be computed in the most sensible way for your platform. That might involve loading it as a constant, or that might involve computing it. Or who knows, your compiler might change T(0.5)*a to a/2 if that gives the same results.

In your question you give an example of adding a numeric_traits helper class. This, IMO, is overkill. In the extremely unlikely case that constexpr makes a difference, you can just write

template <typename T>
T get_half(T a) {
    constexpr T half = 0.5;
    return half * a;
}

However, this still does more harm than good, in my opinion: your get_half can now no longer be used with non-literal types. It requires the type to support conversions from double in constant expressions. Suppose you have an arbitrary-precision rational type, written without constexpr in mind. Now your get_half can not be used, because the initialisation constexpr T half = 0.5; is invalid, even if 0.5 * a might otherwise have compiled.

This is the case even with your numeric_traits helper class; it's not invalid just because I moved it into the function body.

  • thank you for your answer. I know that the compiler might optimize something like T(0.5). I guess my question is what the best practice is if I want to be 101% sure that a double constant will be double and a float constant will be float. For instance, I could use constexpr within a numeric traits class in C++11. Is there another solution? – Alejandro Feb 10 '15 at 14:26
  • @LightnessRacesinOrbit thank you. I guess I would like to know the opinion of people with more experience and best practices. Also what would the solution be using c++98 (no c++11 features)? – Alejandro Feb 10 '15 at 15:44
  • @Alejandro I responded to that bit: it would be possible, but `numeric_traits` is more than needed for that approach. However, in my opinion, it would do more harm than good. –  Feb 10 '15 at 16:00