Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the return statement allowed on constexpr constructors?

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:

  • an asm declaration
  • a goto statement
  • a try-block
  • a definition of a variable of non-literal type or of static or thread storage duration or for which no initialization is performed

It 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.

like image 733
Kalrish Avatar asked Sep 19 '14 20:09

Kalrish


People also ask

Can constructors be constexpr?

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.

What functions can be constexpr?

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 throw exception?

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.


2 Answers

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_asserts are.

like image 51
T.C. Avatar answered Oct 10 '22 09:10

T.C.


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.

like image 37
Shafik Yaghmour Avatar answered Oct 10 '22 11:10

Shafik Yaghmour