As explained in this page, the compound statement of the body of a constexpr
constructor, if it is not deleted nor defaulted, must satisfy the constraints for the body of a constexpr
function, that is, it may contain any statements except:
asm
declarationgoto
statementtry
-blockIt seems that the standard does not restrict the number of return
statements that may appear, whereas, in C++11, only one was allowed.
Now, consider the following code:
class Thing
{
public:
// Shouldn't this constructor be fine under both C++11 and C++14?
constexpr Thing ( )
{
return;
}
};
int main ( )
{
Thing a_nice_thing;
}
Clang (3.5 with -std=c++14) compiles it fine, but GCC (4.9.1 with -std=c++14) does not, complaining:
constexpr constructor does not have empty body
However, if it is changed:
class Thing
{
public:
// This constructor is fine under both C++11 and C++14
constexpr Thing ( )
{
static_assert( __cplusplus > 1 , "static_assert isn't the right mechanism to test this, since it wasn't available at earlier versions of the language" );
}
};
int main ( )
{
Thing a_nice_thing;
}
Then it compiles fine under both compilers.
Since GCC complains about the constructor's body not being empty, shouldn't it also complain in the later case? Is this behavior a bug in GCC? Is the return statement allowed on constexpr constructors?
Note: whether a single return
statement is really worth is not the scope of this question, although interesting and perhaps worth another one. I put single return
statements on constructors whose body is empty, for style reasons.
A constructor that is declared with a constexpr specifier is a constexpr constructor. Previously, only expressions of built-in types could be valid constant expressions. With constexpr constructors, objects of user-defined types can be included in valid constant expressions.
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.
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.
Even though try blocks and inline assembly are allowed in constexpr functions, throwing exceptions or executing the assembly is still disallowed in a constant expression.
GCC currently doesn't support C++14's version of constexpr
, so even with -std=c++14
you still get C++11's constexpr
.
The C++11 restriction on the body of constexpr
constructors is (§7.1.5 [dcl.constexpr]/p4):
the compound-statement of its function-body shall contain only
- null statements,
- static_assert-declarations
typedef
declarations and alias-declarations that do not define classes or enumerations,- using-declarations,
- and using-directives;
(There are lots of other restrictions as well; I limited the quote to the one relevant to the question.)
return
statements are not allowed in constexpr
constructors in C++11, while static_assert
s are.
C++14 it changed, as covered by the draft C++14 standard section 7.1.5 The constexpr specifier
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
and a constructor must follow the additional restrictons:
— either its function-body shall be = default, or the compound-statement of its function-body shall satisfy the constraints for a function-body of a constexpr function;
— every non-variant non-static data member and base class sub-object shall be initialized (12.6.2);
— if the class is a union having variant members (9.5), exactly one of them shall be initialized;
— if the class is a union-like class, but is not a union, for each of its anonymous union members having variant members, exactly one of them shall be initialized;
— for a non-delegating constructor, every constructor selected to initialize non-static data members and base class sub-objects shall be a constexpr constructor;
— for a delegating constructor, the target constructor shall be a constexpr constructor.
and it does not prevent a return statement nor a static_assert
.
in C++11 it included the restrictions:
— the compound-statement of its function-body shall contain only
— null statements,
— static_assert-declarations
— typedef declarations and alias-declarations that do not define classes or enumerations,
— using-declarations,
— and using-directives
which does not allow a return statement.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With