ISO/IEC JTC1 SC22 WG21
N3598
Richard Smith
2013-03-12
In C++11, constexpr member functions are implicitly const. This creates problems for literal class types which desire to be usable both within constant expressions and outside them:
struct A {
constexpr A() : n(3) {}
constexpr int getN() const /*implicit*/ { return n; }
int n;
};
struct B {
constexpr B() : a() {}
constexpr const A &getA() const /*implicit*/ { return a; }
A &getA() { return a; } // cannot make this 'constexpr'
A a;
};
constexpr int n = B().getA().getN(); // error, selected overload for
// B::getA() is not constexpr.
This problem only exists for the implicit this parameter to a function; constexpr functions can have parameters of (non-const) T * and T &.
Several alternatives have been suggested to resolve this problem:
If we select the second option, the backwards-compatibility issue can be made less severe by encouraging implementors to diagnose constexpr but not explicitly const member functions in their C++11 modes.
Change in [dcl.constexpr] (7.1.5)/6:
If the instantiated template specialization of a constexpr function template or member function of a class template would fail to satisfy the requirements for a constexpr function or constexpr constructor, that specialization is not a constexpr function or constexpr constructor.[ Note: If the function is a member function it will still be const as described below. — end note ]If no specialization of the template would yield a constexpr function or constexpr constructor, the program is ill-formed; no diagnostic required.
Change in [dcl.constexpr] (7.1.5)/8:
A constexpr specifier for a non-static member function that is not a constructor declares that member function to be const (9.3.1). [ Note:The constexpr specifier has noothereffect on thefunctiontype of a constexpr function or a constexpr constructor.— end note ] The keyword const is ignored if it appears in the cv-qualifier-seq of the function declarator of the declaration of such a member function.The class of whichthata constexpr function is a member shall be a literal type (3.9). [ Example:class debug_flag { public: explicit debug_flag(bool); constexpr bool is_on() const; // error: debug_flag not // literal type private: bool flag; }; constexpr int bar(int x, int y) // OK { return x + y + x*y; } // ... int bar(int x, int y) // error: redefinition of bar { return x * 2 + 3 * y; }— end example ]
Strawman syntax: allow mutable in the location where const
would be written: constexpr A &getA() mutable { return
a; }
Change the grammar for parameters-and-qualifiers in [dcl.decl] (8)/4:
parameters-and-qualifiers:
(
parameter-declaration-clause)
mutableopt cv-qualifier-seqopt ref-qualifieropt exception-specificationopt attribute-specifier-seqopt
Change in [dcl.fct] (8.3.5)/1:
In a declarationT D
whereD
has the form
D1 (
parameter-declaration-clause)
mutableopt cv-qualifier-seqopt ref-qualifieropt exception-specificationopt attribute-specifier-seqopt [...]
Change in [dcl.fct] (8.3.5)/2:
In a declarationT D
whereD
has the form
D1 (
parameter-declaration-clause)
mutableopt cv-qualifier-seqopt ref-qualifieropt exception-specificationopt attribute-specifier-seqopt trailing-return-type [...]
Add a new paragraph after [dcl.fct] (8.3.5)/6:
Ifmutable
is part of a function declarator,const
shall not be present in the cv-qualifier-seq and that declarator shall be used to declare a non-static member function. [ Note: Such a function is notconst
even if it is declared with theconstexpr
specifier. — end note ]
Change in [dcl.constexpr] (7.1.5)/8:
A constexpr specifier for a non-static member function that is
not a constructor and is not declared with the mutable
keyword declares that member function to be const
(9.3.1). [ Note: The constexpr specifier has no
other effect on the function type. — end note ] The keyword
const is ignored if it appears in the cv-qualifier-seq of
the function declarator of the declaration of such a member function.
The class of which that function is a member shall be a literal type (3.9). [
Example: [...] — end example ]