Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What C++14 rule prohibits constexpr functions from making assignments to data members?

My understanding is that this (nonsensical) code is not valid C++14:

class Point  {
public:
  constexpr double setX(double newX) { return x = newX; }
private:
  double x;
};

I'm trying to figure out what part of the (still officially draft) C++14 Standard disallows it. The restrictions on constexpr functions are listed in 7.1.5/2. (Sorry for the mangled formatting. I can't figure out how to beat markdown into making it look right.)

The definition of a constexpr function shall satisfy the following constraints:

  • it shall not be virtual (10.3);
  • its return type shall be a literal type;
  • each of its parameter types shall be a literal type;
  • its function-body shall be = delete, = default, or a compound-statement that does not contain
    • an asm-definition,
    • a goto statement,
    • a try-block, or
    • a definition of a variable of non-literal type or of static or thread storage duration or for which no initialization is performed.

There's nothing there that prohibits assignments to data members. There is such a prohibition in 5.19/2 (bullet 15) (again with mangled formatting, sorry):

A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions: [...] modification of an object (5.17, 5.2.6, 5.3.2) unless it is applied to a non-volatile lvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;

But I don't see how 5.19 applies to 7.1.5. Can somebody clarify?

like image 662
KnowItAllWannabe Avatar asked Aug 06 '14 04:08

KnowItAllWannabe


People also ask

What is a constexpr function C++?

constexpr functions A constexpr function is one whose return value is computable at compile time when consuming code requires it. Consuming code requires the return value at compile time to initialize a constexpr variable, or to provide a non-type template argument.

Can a member function be constexpr?

const can only be used with non-static member functions whereas constexpr can be used with member and non-member functions, even with constructors but with condition that argument and return type must be of literal types.

Can constexpr be modified?

A template metaprogram runs at compile, but a constexpr function can run at compile time or runtime. Arguments of a template metaprogram can be types, non-types such as int , or templates. There is no state at compile time and, therefore, no modification.

Is constexpr can be used with #define macros?

Absolutely not. Not even close. Apart from the fact your macro is an int and your constexpr unsigned is an unsigned , there are important differences and macros only have one advantage.


1 Answers

It is valid C++14. You can modify members of a literal class type as long as the lifetime of the object is contained within the evaluation of the constant expression.

The use of Point in a constant expression is controversial (CWG DR 1452), but it is allowed by current implementations. It would be a literal class except that it is not aggregate (§3.9.1/10) because it has a private field (§8.5.1/1). However its construction does not invoke its non-constexpr constructor because it is trivially-constructible. Anyway, this issue is fixed by adding a declaration constexpr Point() = default;.

§5.19 restricts what can be evaluated in a constant expression. One restriction is that only constexpr functions may be entered. §7.1.5 specifies what functions may be marked constexpr, but note that constexpr functions may contain (in a conditional statement) things that cannot be evaluated in a constant expression.

See the proposal papers, second and first drafts.

like image 108
Potatoswatter Avatar answered Sep 25 '22 20:09

Potatoswatter