4

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.

john
  • 85,011
  • 4
  • 57
  • 81
M H
  • 41
  • 3
  • There's no way to answer this question except by looking at the generated code. The C++ standard does not tell compilers how they must compile their code. – john Aug 16 '19 at 08:17
  • Your code isn't valid, you try to convert `const double` to `const double *` here `func`. – t.niese Aug 16 '19 at 08:18
  • FWIW on my compiler `func` was reduced to a multiplication by a constant (and `func2` was inlined as well) but YMMV. – john Aug 16 '19 at 08:28
  • 1
    I edited the code to what the OP clearly intended. – john Aug 16 '19 at 08:29
  • 1
    For `func<&p1,&p2,&p3>(c)` the compiler would be allowed to optimize the code to `c * 0.5 + 2.5`. As these addresses won't refer to mutable data or addresses. – t.niese Aug 16 '19 at 08:36
  • 1
    For your convenience, here is what the three largest compilers do with your code: https://godbolt.org/z/EeoO8v – Max Langhof Aug 16 '19 at 08:40
  • Thanks, when I changed my code(of course I don't use names like func, func2, a, b...) I removed the &'s. – M H Aug 17 '19 at 08:04

3 Answers3

8

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.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
6

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

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.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165