3

Consider the following header file, which consists of slow constexpr function, which is used to initialize a global variable:

constexpr int slow_func() {
    for (int i = 0; i < 100*1024*100; ++i)
            ;
    return 0;
}

constexpr int g_val = slow_func();

Calling this function takes ~10s

Now, if this header gets #included in multiple translation units, the compilation time increases by each translation unit that #includes this file

With hundreds of translations units, compilation now takes an unreasonable amount of time.

Since this is a constexpr function, I assumed that the compiler would evaluate the return value of this function only once, and use the same value in the different translation units

Is there a way to tell the compiler to evaluate the value of each 'g_val' only once? If not, what can be done?

I'm currently using g++-5.4, but I suppose the standard mandates this behaviour (Even though I didn't find it in the current standard)

Mikrosaft
  • 195
  • 1
  • 8
  • AFAIK it cant do that only once, each translation unit is independent from any other, and so when it compiles one it will go through and see this and evaluate if need be, which it needs to since g_val is int the header. Maybe you can do some extern trickery to get g_val in a c++ and have it evalute only for that one... – Borgleader Apr 28 '17 at 20:30
  • Are you familiar with how `include` works? It copy-pastes the contents of `include`d file, in-place of `#include` directive. This is done _before_ compilation. Then compiler just compiles each translation unit one-by-one, and it can't know that similar-looking code is somehow related (e.g. `#include`d from somewhere else). What you probably would want to look into is: _precompiled headers_. – Algirdas Preidžius Apr 28 '17 at 20:33
  • 1
    Each translation unit is translated as a unit, isn't it? In other words, the unit of translation is one translation unit. – Kerrek SB Apr 28 '17 at 20:35
  • I think that if you compile with C++17, you will see that `g_val` will get evaluated only once, as it is implicitly `inline`. – Rakete1111 Apr 28 '17 at 20:36
  • `constexpr` is not a *guarantee* that a function *will* be evaluated at compile time. It may still be emitted as a run-time function if called with *non*-`constexpr` arguments. – Jesper Juhl Apr 28 '17 at 20:36
  • @Rakete1111 I compiled with -std=c++17. I'm aware that g++-5.4 does not implement all of c++17's features, but I don't have access to a newer version – Mikrosaft Apr 28 '17 at 20:40
  • @Mikrosaft Yeah, only gcc 7 trunk has support for inline variables. Even gcc 6 doesn't support them. – Rakete1111 Apr 28 '17 at 20:41
  • @JesperJuhl True, but g_val does guaranteed to be evaluated at compile time, and this is what I'm interested in – Mikrosaft Apr 28 '17 at 20:42
  • @KerrekSB But is there a way to tell the compiler to evaluate the variable only once? Perhaps indeed with some extern trickery as Borgleader mentioned – Mikrosaft Apr 28 '17 at 20:46
  • @Mikrosaft: Not if you want the value available as a constant expression. If you don't, then you can just define a variable with external linkage in one single TU. – Kerrek SB Apr 28 '17 at 20:47
  • @KerrekSB I must have this value be a constexpr. So I guess there's nothing to do about the issue? – Mikrosaft Apr 28 '17 at 20:53
  • @Mikrosaft: See if your compiler supports precompiled headers, as was suggested above? – Kerrek SB Apr 28 '17 at 21:01

1 Answers1

1

Due to how #include works, you'd be better off making the variable somewhere once, then making it a global variable, forward declared(by #including the forw. dec.) in all your translation units. This is so it only has to compile once, but anywhere it's forward declared can use it.

Of course, it'll then be a global variable, so there are downsides to that as well. But making it a global should stop it being recompiled.

Apitosu
  • 86
  • 5