Topic: Where in the C++11 standard does it specify when a constexpr
Author: sschurr<s.scott.schurr@googlemail.com>
Date: Fri, 14 Dec 2012 09:15:08 -0800 (PST)
Raw View
Hi folks,
I asked this question on Stack Overflow yesterday. The full
text of the question and the answers can be found here:
http://stackoverflow.com/questions/13571749/where-in-the-c11-standard-does-it-specify-when-a-constexpr-function-can-be-eva
The heart of the question is this:
<quote>
I've been looking through the C++11 FDIS (N3242, available
at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/)
to try and determine two things:
o When is the compiler obligated to evaluate a constexpr
function during translation?
o When is the compiler allowed to evaluate a constexpr
function during translation?
[...snip...]
What I'm particularly interested in discovering is whether
constexpr evaluation during translation is triggered by:
1. When all parameters passed to the constexpr function
are literals, or
2. The implied object argument during overload resolution
(Section 13.3.1 Paragraph 3) is either constexpr or
requires a literal (such as for array dimensions), or
3. Something else entirely.
Please, if possible, in your responses cite sections of
the FDIS that I can look up or key phrases I can search
in the FDIS.
</quote>
The consensus on Stack Overflow seems to be that the
standard has nothing explicit to say on the matter. I
concur that's possible -- I personally found no hint of
it. But I suspect I'm missing something.
The feeling I get from examining the behavior of g++ 4.7
is that it uses approach 2. But I could be wrong. And
other compilers may possibly take other approaches.
So I thought I would ask the folks who have lived the
standard.
Thanks very much for the help.
SSchurr
--
[ comp.std.c++ is moderated. To submit articles, try posting with your ]
[ newsreader. If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: =?windows-1252?Q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Sat, 15 Dec 2012 10:54:25 -0800 (PST)
Raw View
Am 14.12.2012 18:15, schrieb sschurr:
> The heart of the question is this:
>
> <quote>
>
> I've been looking through the C++11 FDIS (N3242, available
> at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/)
> to try and determine two things:
>
> o When is the compiler obligated to evaluate a constexpr
> function during translation?
>
> o When is the compiler allowed to evaluate a constexpr
> function during translation?
>
> [...snip...]
Answers to these questions are related to the context, in which a
constexpr function is used. I would like to warn you that the standard
itself is not a document that is written to answer such questions
directly. If you want to enumerate these cases, you have to read through
all the standard and have to find those places that impose such a
requirement. This is extremely hard work and I'm not willing to do that
at the moment ;-) But if you are willing to accept some general
conclusions this can lead to still useful rules of the thumb.
One of the simplest rules for your first question is IMO: If a constexpr
function occurs in a context that requires a constant expression, it
must be evaluated during translation. This rule is a simplification in
the regard that it doesn't need to hold when an implementation can
realize this during runtime without affecting the observable behaviour.
Especially 3.6.2 is enlightening in this context:
"An implementation is permitted to perform the initialization of a
non-local variable with static storage duration as a static
initialization even if such initialization is not required to be done
statically, provided that [.. (enumeration of cases)]"
This also is related to one of the key concepts of C++: Observable
behaviour which is defined in 1.9.
> What I'm particularly interested in discovering is whether
> constexpr evaluation during translation is triggered by:
>
> 1. When all parameters passed to the constexpr function
> are literals, or
Just the fact that a constexpr function is called and parameters that
are passed as literals doesn't impose any requirement that the function
will be called during compile-time. There is no direct requirement in
the standard (so I cannot point to such wording), but there is a note in
5.19 that makes that clear (see p. 4)
"[ Note: Although in some contexts constant expressions must be
evaluated during program translation, others may be evaluated during
program execution. Since this International Standard imposes no
restrictions on the accuracy of floating-point operations, it is
unspecified whether the evaluation of a floating-point expression
during translation yields the same result as the evaluation of the same
expression (or the same operations on the same values) during program
execution.85 [ Example:
bool f() {
char array[1 + int(1 + 0.2 - 0.1 - 0.1)]; // Must be evaluated during
// translation
int size = 1 + int(1 + 0.2 - 0.1 - 0.1); // May be evaluated at
// runtime
return sizeof(array) == size;
}
It is unspecified whether the value of f() will be true or false. end
example ] end note ]"
This note helps to see that even though the expression int(1 + 0.2 - 0.1
- 0.1) contains only literals as "arguments", it may be evaluated during
runtime. This sentence does not directly refer to constexpr functions,
but that is not very important as evidence, because the specification of
constexpr functions is intimately related to constant expressions. In
other contexts constexpr function don't differ from other functions, see
e.g. 7.1.5 p7:
"A call to a constexpr function produces the same result as a call to an
equivalent non-constexpr function in all respects except that a call to
a constexpr function can appear in a constant expression."
To give a more specific example, consider this one:
include <iostream>
constexpr int foo(int v) { return v; }
int main() {
int i = foo(42);
std::cout << i << std::endl;
}
In this example foo is called like any other function, even though it is
called with a "literal" as argument value. There is nothing in the
standard that requires that foo(42) is evaluated during compile-time. To
make the example a little bit more interesting, consider this one:
#include <iostream>
constexpr int inverse(int v) { return 1/v; }
int main() {
int i = inverse(0);
std::cout << i << std::endl;
}
This program is "illformed, but diagnostic required", because during
runtime a division by zero occurs. You may find compilers that will
reject this program, but they are not *required* to do so. E.g. gcc 4.8
accepts it without batting an eye, but an attempt to run this program
leads to an immediate hard crash.
> 2. The implied object argument during overload resolution
> (Section 13.3.1 Paragraph 3) is either constexpr or
> requires a literal (such as for array dimensions), or
The implied object argument doesn't play a special role in constant
expressions. An important set of rules are specified in 5.19 and they
decide which context is considered to be a constant expression. The
wording was not written to satisfy your assumed rule above. So why
should that be relevant? If the standard committee would have preferred
such a rule, they could have specified it. But there is no such (direct)
wording.
> The consensus on Stack Overflow seems to be that the
> standard has nothing explicit to say on the matter. I
> concur that's possible -- I personally found no hint of
> it. But I suspect I'm missing something.
Why do you think so? There are many possible questions that can be asked
and the standard won't provide direct answers for them.
> The feeling I get from examining the behavior of g++ 4.7
> is that it uses approach 2. But I could be wrong. And
> other compilers may possibly take other approaches.
Why would you consider a positive or negative answer to that question as
important? The standard doesn't typically depend on "literals" or
"objects marked as constexpr". The standard imposes requirements, in
which context constant expressions are required (with several different
sub-categories), and it also specifies observable behaviour. If a
compiler does not violate these requirements, there is anything
possible. Even though this is true by theory, you will find that todays
compilers often use specific, sometimes similar, technical means to
realize that, therefore by simple observation you might find that they
have something in common even though the standard doesn't require that.
You really shouldn't rely on that behaviour nor should you conclude that
out of these observations would follow that this is required by the
standard.
HTH & Greetings from Bremen,
Daniel Kr gler
--
[ comp.std.c++ is moderated. To submit articles, try posting with your ]
[ newsreader. If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]