Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

constexpr and the ordering and omission of specifiers and cv qualifiers #1086

Open
eggrobin opened this issue Jul 4, 2016 · 0 comments
Open

Comments

@eggrobin
Copy link
Member

eggrobin commented Jul 4, 2016

constexpr is a declaration specifier, but not a cv qualifier, thus may appear in the decl-specifier-seq, but not in the declarator; in other words, for the purposes of variable declarations, it's the same grammatical animal as static, although it has an influence on the type.
These gory details mean that the following compiles, and the commented-out line is indeed erroneous (and yes, U+066D ARABIC FIVE POINTED STAR (٭) is allowed in identifiers).

#include <type_traits>

#define ASSERT_TYPE(expression, type)                              \
    static_assert(std::is_same<decltype(expression), type>::value, \
                  #expression " does not have type " #type)

constexpr int*       constexpr_int٭       = nullptr;
constexpr int* const constexpr_int٭_const = nullptr;
constexpr int const* constexpr_int_const٭ = nullptr;

const int*           const_int٭           = nullptr;
const int* const     const_int٭_const     = nullptr;

//\
int* constexpr       int٭_constexpr       = nullptr;  // parse error
int constexpr*       int_constexpr٭       = nullptr;
int const constexpr* int_const_constexpr٭ = nullptr;
int constexpr const* int_constexpr_const٭ = nullptr;

int* const           int٭_const           = nullptr;
int const*           int_const٭           = nullptr;
int const* const     int_const٭_const     = nullptr;

ASSERT_TYPE(constexpr_int٭,             int* const);
ASSERT_TYPE(constexpr_int٭_const,       int* const);
ASSERT_TYPE(constexpr_int_const٭,       int const* const);

ASSERT_TYPE(const_int٭,                 int const*);
ASSERT_TYPE(const_int٭_const,           int const* const);

ASSERT_TYPE(int_constexpr٭,             int* const);
ASSERT_TYPE(int_const_constexpr٭,       int const* const);
ASSERT_TYPE(int_constexpr_const٭,       int const* const);

ASSERT_TYPE(int٭_const,                 int* const);
ASSERT_TYPE(int_const٭,                 int const*);
ASSERT_TYPE(int_const٭_const,           int const* const);

In other words, replacing constexpr by const or vice-versa in a correct variable declaration may yield an ungrammatical declaration, or a correct declaration with a different type, since constexpr applies constness at the top level.

Decision.

Write constexpr initially.
For constexpr member variables, write static constexpr rather than constexpr static.

The following still stand:

Keep cv-qualifiers that are part of the decl-specifier-seq at the end of the decl-specifier-seq, and the same for type-specifier-seq: T const rather than const T.
Omit redundant specifiers: final const on constexpr variables, static on declarations at namespace scope, inline on constexpr functions and constructors*.

Example:

constexpr Length Chain;  // OK.
constexpr Length const Furlong;  // Redundant |const|.
Length constexpr Rod;  // Misleading |constexpr| placement.

* See the standard, 7.1.5(2).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant