using const double* const as a template parameter - code perfomance question

353 Views Asked by At

I'm trying to understand the under the hood of using const double* const as template. I have some very basic calculation I want to perform efficiently and I don't know how the c++ compiler works(what is the assembly code).

The idea is to create a template for a function that get 3 constant doubles as template parameters and a double as an argument.

constexpr double p1 = 1;
constexpr double p2 = 2;
constexpr double p3 = 3;

template <const double* const a, 
        const double* const b, 
        const double* const c>
inline double func(double value)
{
    constexpr double d = *a - *b;
    constexpr double e = *a - *c;
    constexpr double ratio = d / e;
    constexpr double remain = *c - *a * ratio;

    return value * ratio + remain;
}

double func2(double c)
{
    return func<&p1,&p2,&p3>(c);
}

My question is if for every p1,p2,p3 the func< p1,p2,p3 >(c) will be compiled to c * < const value > + < const value >

or the compiler can't extract the const values in compilation time and the full function will execute in run time.

3

There are 3 best solutions below

0
Konrad Rudolph On

When looking at the compiled output you can see that the compiler reduces func2 to a multiplication and an addition with two constants. It doesn’t even call func any more.

However, the compiler is perfectly capable of producing the same code without the need to muck around with non-type template arguments:

inline double func(
    double const a,
    double const b,
    double const c,
    double const value
) {
    double const d = a - b;
    double const e = a - c;
    double const ratio = d / e;
    double const remain = c - a * ratio;

    return value * ratio + remain;
}

This produces the exact same output.

0
Martin Bonner supports Monica On

The standard doesn't say. It doesn't even say that the code must be compiled - it could be interpreted.

In practise, every current C++ does compile (although some compile to a bytecode which is then JITed). Furthermore, every compiler I know about will avoid doing a division at runtime in optimized builds. (In non-optimized builds, all bets are off).

The only way to be sure is to look at the generated assembly - Godbolt.org is very good for this.

0
Pete Becker On

In general, C++ doesn't require evaluation of floating-point expressions at compile time. That's because floating-point typically has knobs that you can tweak at runtime, such as changing the rounding mode, so anything evaluated at compile-time could easily run afoul of runtime changes to the behavior of floating-point arithmetic.

That's reflected in the requirement that non-type template arguments can't be floating-point values. So, for example, with template <auto n> struct B { };, B<2.5> is an error.

In this question, the template is being instantiated with a pointer. That's okay; the fact that the pointer points at a double does not invalidate it. Nonetheless, as you've seen, the compiler won't calculate the result at compile-time. So all those constexpr markers aren't doing anything; the results are all evaluated at runtime.