31

I'm having some trouble with constexpr. The book C++ Primer shows a line of code:

 constexpr int sz = size(); // only size() is a constexpr function // this code is right 

However the book doesn't give a specific example. So I try the following code by myself:

#include <iostream> constexpr int fun(); int main() { constexpr int f = fun(); std::cout << f << std::endl; } constexpr int fun() { return 3; } 

But clang 3.4.1 says:

undefined function 'fun' cannot be used in a constant expression

If I change constexpr into const, it works well, and if I change my code to define the constexpr function before use:

#include <iostream> constexpr int fun() { return 3; } int main() { constexpr int f = fun(); std::cout << f << std::endl; } 

It also works well. Can someone tell me why?

0

2 Answers 2

24

A constexpr function does NOT have to be defined before its first use, however the result of any call made prior to definition is not a constant expression.

Source: C++ Standard draft n4296, section 5.20:

A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:

  • this, except in a constexpr function or a constexpr constructor that is being evaluated as part of e;
  • an invocation of a function other than a constexpr constructor for a literal class, a constexpr function, or an implicit invocation of a trivial destructor [ Note: Overload resolution is applied as usual — end note ];
  • an invocation of an undefined constexpr function or an undefined constexpr constructor;
  • ...

version from draft 3485 (section 5.19):

A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression, but subexpressions of logical AND, logical OR, and conditional operations that are not evaluated are not considered [ Note: An overloaded operator invokes a function. — end note ]:

  • this [ Note: when evaluating a constant expression, function invocation substitution replaces each occurrence of this in a constexpr member function with a pointer to the class object. — end note ];
  • an invocation of a function other than a constexpr constructor for a literal class or a constexpr function [ Note: Overload resolution is applied as usual — end note ];
  • an invocation of an undefined constexpr function or an undefined constexpr constructor
  • ...

The example int x2 = s. t(); in n2235 actually became valid due to the changes made prior to Standardization. However, constexpr int x2 = s. t(); remains an error.

Sign up to request clarification or add additional context in comments.

9 Comments

@kvorobiev: I'm quoting from a draft because it is public. The rule was introduced quite a few drafts earlier, and is part of the official Standard.
Can you explain why?
@BenVoigt: That still doesn't in itself explain why the definition needs to already have been seen, lexically. I imagine the phrase "single pass" comes into the answer somehow :)
@lightness C++ compilers are not single pass, though. The restriction is still valuable in preventing circular type dependencies, however.
@BenVoigt: The reason I ask is that someone posted a near-duplicate of this question yesterday, but felt that these answers don't amply explain the rationale behind the standard wording. I was hoping we could beef them up a little in that regard. :)
|
3

A constant expression function must be defined before its first use. See this paper, end of section 4.1.

3 Comments

So then the book is in error? Perhaps some compilers accept this syntax despite not being allowed by the standard?
According to this table few compilers support constexpr now and I doubt that one of them supports this syntax.
@kvorobiev but the most important compilers are quite C++11-ready, in particular g++/clang++. MSVC not yet, but getting there.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.