6

This is more of a philosophical question rather than practical code snippet, but perhaps C++ gurus can enlighten me (and apologies if it's been asked already).

I have been reading Item 15 in Meyers's "Effective Modern C++" book, as well as this thread: implicit constexpr? (plus a reasonable amount of googling). The item goes over usage of constexpr for expressions, namely that it defines functions that can return compile time values given compile time inputs. Moreover, the StackOverflow thread I referred to shows that some compilers are perfectly capable of figuring out for themselves which function invocation results are known at compile time.

Hence the question: why was constexpr added to the standard as compared to defining when compilers should derive and allow static/compile-time values?

I realise it makes various compile-only (e.g. std::array<T, constexpr>) definitions less predictable, but on the other hand, as per Meyers's book, constexpr is a part of the interface,..., if you remove it, you may cause arbitrarily large amounts of client code to stop compiling. So, not only having explicit constexpr requires people to remember adding it, it also adds permanent semantics to the interface.

Clarification: This question is not about why constexpr should be used. I appreciate that having an ability to programatically derive compile-time values is very useful, and employed it myself on a number of occasions. It's a question on why it is mandatory in situations where compiler may deduce const-time behaviour on its own.

Clarification no. 2: Here is a code snippet showing that compilers do not deduce that automatically, I've used g++ in this case.

#include <array>

size_t test()
  {
  return 42;
  }

int main()
  {
  auto i = test();
  std::array<int, i> arrayTst;
  arrayTst[1] = 20;
  return arrayTst[1];
  }

std::array declaration fails to compile because I have not defined test() as constexpr, which is of course as per standard. If the standard were different, nothing would have prevented gcc from figuring out independently that test() always returns a constant expression.

This question does not ask "what the standard defines", but rather "why the standard is the way it is"?

Community
  • 1
  • 1
RomanK
  • 1,258
  • 7
  • 18
  • Might be helpful: http://www.stroustrup.com/C++11FAQ.html#constexpr. – R Sahu Mar 02 '15 at 23:20
  • Without putting much though into my answer, magic values are bad, if your code automatically computes them from easy to understand parameters, then that's a big win in and of itself. For example I wrote some code to compute a crc32 at compile time with constexpr just today, and I think it's much more readable to have a function call to a constexpr that you can clearly follow, rather than a magic value computed who knows how. You also get the *guarantee* that things are computed at compile time, this actually saved my life once in a situation where static global initialization would not run. – tux3 Mar 02 '15 at 23:21
  • @tux3: Sure, but there's no reason you couldn't have used a plain (non `constexpr` function) to do the same thing before. – Billy ONeal Mar 02 '15 at 23:22
  • `constexpr` is a guarantee of the interface: you can use this function (for certain inputs) where a constant expression is required, using **any** conforming compiler. The specification of `constexpr` defines the minimum capabilities that a conforming compiler must support when evaluating constant expressions. – dyp Mar 02 '15 at 23:22
  • @BillyONeal well, with a plain function you pointlessly lose some performance. If it's a trivial constant, it doesn't matter much, but when you have large arrays of them the gains can be significant. – tux3 Mar 02 '15 at 23:24
  • @tux3 - Thanks for the answer, but I'm not saying that magic values should be used instead of `constexpr`. Rather at the language level, we could say that if a function answers certain criteria, it shall provide a compile-time value given compile-time input, such as your crc32 example. Similarly on @dyp 's answer - we could theoretically say that a compiler is conforming if and only if it provides compile-time values in certain circumstances. Same circumstances where `constexpr` is allowed with C++11/14. – RomanK Mar 02 '15 at 23:27
  • @tux: If it was a trivial constant the inliner could have inlined the calculation without constexpr. constexpr doesn't even require that the compiler compute the value at compile time -- only that if the value is needed at compile time, it is available. – Billy ONeal Mar 02 '15 at 23:33
  • @RomanK sorry, I wasn't really addressing your points. I think that the part where you get a guarantee of behavior and interface is crucial as others pointed out, without it you might silently turn a compile time computation into runtime. This would also introduce even more inconsistencies between compilers, but that isn't such a problem at this point. – tux3 Mar 02 '15 at 23:33
  • 1
    @BillyONeal I don't think you can put simple constant folding on the same level as constexpr. Constexpr allows you to run much more complicated algorithms at compile time with an actual guarantee. – tux3 Mar 02 '15 at 23:37
  • @RomanK Requiring a function that can be evaluated inside a constant expression to be declared as `constexpr` was in fact not part of the [original proposal](http://open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1521.pdf). It appeared in Revision 2 of that paper; I'm still trying to figure out the rationale. – dyp Mar 02 '15 at 23:40
  • [see this answer](http://stackoverflow.com/a/28821610/1090079) for a detailed explanation of the usefulness of *constexpr*. – Filip Roséen - refp Mar 02 '15 at 23:51
  • Thanks @dyp - this was pretty much the gist of my question. @FilipRoséen-refp - that's a very good pointer. Maybe I should have revived that question instead of creating a new one. Your answer there is very reasonable, but just to play devil's advocate - why not make `constexpr` optional? I.e. if I really want to impose a contract, I can, but I don't absolutely have to do it in obvious cases such as example above. – RomanK Mar 03 '15 at 12:59

1 Answers1

6

Before constexpr the compilers could sometimes figure out a compile time constant and use it. However, the programmer could never know when this would happen.

Afterwards, the programmer is immediately informed if an expression is not a compile time constant and he or she realizes the need to fix it.

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131
  • 1
    Thanks for the quick answer. Hypothetically speaking, why couldn't `constexpr` be optional? I.e., if I feel so inclined, I could add the keyword to get notified if the expression is not constant (as you described), but still get benefit of compile time evaluations if I omitted it (including template args etc.) – RomanK Mar 02 '15 at 23:24
  • @RomanK: Do you have evidence that you don't get that already? – Zan Lynx Mar 03 '15 at 01:17
  • Yes, I added an example to the question. If compilers did it, that would be against the standard. – RomanK Mar 03 '15 at 06:43