Allow constexpr static data members in a literal type.

340 views
Skip to first unread message

Avi Kivity

unread,
Mar 26, 2017, 10:30:29 AM3/26/17
to ISO C++ Standard - Future Proposals
Consider this type-safe bool class:


template <typename Tag>

class bool_class {

bool _value;

public:

explicit constexpr bool_class(bool v) noexcept : _value(v) {}

// more emulation of bool

static constexpr bool_class yes = bool_class{true};

static constexpr bool_class no = bool_class{true};

};


Compilation fails, I believe rightly, on clang, because by the time yes
and no are parsed, bool_class is an incomplete type, and therefore not a
literal type. It could be worked around by making yes and no functions.

Should we make this legal? It seems reasonable for types to offer
constants scoped under their own name, and if they are literal types,
that these constants can be constexpr.

Ville Voutilainen

unread,
Mar 26, 2017, 10:35:41 AM3/26/17
to ISO C++ Standard - Future Proposals
This is US 24 in
http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0488r0.pdf. The
comment was rejected
for C++17 due to lack of a proper proposal and the timing.

Nicol Bolas

unread,
Mar 26, 2017, 10:35:44 AM3/26/17
to ISO C++ Standard - Future Proposals

How does it seem reasonable to define variables of a type that has not yet been defined? What's wrong with defining them outside of the scope of the class?

Avi Kivity

unread,
Mar 26, 2017, 10:49:22 AM3/26/17
to std-pr...@isocpp.org
You can do that already, within an inline member function.


What's wrong with defining them outside of the scope of the class?


You have to invent a scope for them.

Perhaps


   template <typename Tag>

   class bool_class {

       bool _value;

   public:

       explicit constexpr bool_class(bool v) noexcept : _value(v) {}

       // more emulation of bool

       struct constants;

   };


   template <typenamer Tag>
   struct bool_class<Tag>::constants {

       static constexpr bool_class yes = bool_class{true};

       static constexpr bool_class no = bool_class{true};
   };

But using them is awkward and artificial.

Avi Kivity

unread,
Mar 26, 2017, 10:50:39 AM3/26/17
to std-pr...@isocpp.org
Thanks. I hope to see this corrected in the future.

Nicol Bolas

unread,
Mar 26, 2017, 11:22:33 AM3/26/17
to ISO C++ Standard - Future Proposals


On Sunday, March 26, 2017 at 10:49:22 AM UTC-4, Avi Kivity wrote:



On 03/26/2017 05:35 PM, Nicol Bolas wrote:
On Sunday, March 26, 2017 at 10:30:29 AM UTC-4, Avi Kivity wrote:
Consider this type-safe bool class:


   template <typename Tag>

   class bool_class {

       bool _value;

   public:

       explicit constexpr bool_class(bool v) noexcept : _value(v) {}

       // more emulation of bool

       static constexpr bool_class yes = bool_class{true};

       static constexpr bool_class no = bool_class{true};

   };


Compilation fails, I believe rightly, on clang, because by the time yes
and no are parsed, bool_class is an incomplete type, and therefore not a
literal type.  It could be worked around by making yes and no functions.

Should we make this legal?  It seems reasonable for types to offer
constants scoped under their own name, and if they are literal types,
that these constants can be constexpr.

How does it seem reasonable to define variables of a type that has not yet been defined?
You can do that already, within an inline member function.

That's not defining a variable. That's defining a function that returns a value of a certain type.

Vicente J. Botet Escriba

unread,
Mar 26, 2017, 12:50:37 PM3/26/17
to std-pr...@isocpp.org
It seems that you can do

template <typename Tag>

class bool_class {

bool _value;

public:

explicit constexpr bool_class(bool v) noexcept : _value(v) {}

// more emulation of bool

static const bool_class yes;

static const bool_class no;

};

constexpr bool_class bool_class::yes = bool_class{true};

constexpr bool_class bool_class::no = bool_class{true};


Vicente

Avi Kivity

unread,
Mar 27, 2017, 4:08:30 AM3/27/17
to std-pr...@isocpp.org
The function body may define a variable of a certain type.


struct a {
    static constexpr a x{}; // bad
    void f() {
         static constexpr a x{}; // good
    }
};


Technically of course you are correct, but that's because there's a rule that says that functions are fully parsed only after the type is completed, to allow this kind of behavior. I'm asking that this rule be extended to the determination of whether a type is a literal type for the purpose of deciding whether to allow it as a constexpr member.


Avi Kivity

unread,
Mar 27, 2017, 4:13:52 AM3/27/17
to std-pr...@isocpp.org
The compiler (clang) won't recognize yes and no as constexpr variables:


template <typename Tag>
class bool_class {
bool _value;
public:
explicit constexpr bool_class(bool v) noexcept : _value(v) {}

// more emulation of bool
constexpr bool operator==(bool_class other) const {
return _value == other._value;
}

static const bool_class yes;
static const bool_class no;
};

template <typename Tag>
constexpr bool_class<Tag> bool_class<Tag>::yes = bool_class{true};

template <typename Tag>
constexpr bool_class<Tag> bool_class<Tag>::no = bool_class{true};

static_assert(bool_class<int>::yes == bool_class<int>::no);


bool_class2.cc:23:15: error: static_assert expression is not an integral
constant expression
static_assert(bool_class<int>::yes == bool_class<int>::no);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool_class2.cc:23:39: note: read of non-constexpr variable 'no' is not
allowed in a constant expression
static_assert(bool_class<int>::yes == bool_class<int>::no);
^



Jakob Riedle

unread,
Apr 19, 2017, 8:58:54 AM4/19/17
to ISO C++ Standard - Future Proposals
Should we make this legal?  It seems reasonable for types to offer 
constants scoped under their own name, and if they are literal types, 
that these constants can be constexpr. 

I really like the idea of being able to do that and I had that scenario quite often,
e.g. with a Color-Class that defines several constants, such as WHITE, BLACK ...
The problem with defining the attributes outside the class,
is that you cannot declare this stuff in a header file and include it multiple times.

However, this problem is solved by Inline Variables.
Still, having to define constexpr static class variables outside of the class is neither pretty nor intuitive.

Note: Java supports this feature for a long time already.
M(atlab) also supports this. (Using a section named "enumeration" within the "classdef" itself).

Given these reasons, I'm greatly convinced, this is a good thing and should be written a paper for.

HarD Gamer

unread,
Apr 19, 2017, 12:45:15 PM4/19/17
to ISO C++ Standard - Future Proposals

Jakob Riedle

unread,
Apr 29, 2017, 5:51:52 PM4/29/17
to ISO C++ Standard - Future Proposals
Am Mittwoch, 19. April 2017 18:45:15 UTC+2 schrieb HarD Gamer:

This basically represents a work-around but I hardly consider
inline variable definitions outside of the class in which they are declared as intuitive.


To my knowledge, there are only historical reasons that
static variables of a class should not be defined inside
that class but instead declared inside and defined
outside of the class and in only one source file.

In order to fish or cut bait w.r.t. a proposal, I'd be interested in three things:
1. Are there any reasons against allowing the definition of constexpr static class members of the containing class type within this class itself?
2. Are there any reasons against allowing the definition of (non-constexpr) static class members of the containing class type within this class as well?
3. From question 1 and 2 stems the question: Can we just allow static class members to be defined inside the class itself, as if they'd been defined outside of the class as inline variable?

Am I mistaken at some point?

Richard Smith

unread,
May 2, 2017, 4:43:36 PM5/2/17
to std-pr...@isocpp.org
On 29 April 2017 at 14:51, Jakob Riedle <jakob....@gmail.com> wrote:
Am Mittwoch, 19. April 2017 18:45:15 UTC+2 schrieb HarD Gamer:

This basically represents a work-around but I hardly consider
inline variable definitions outside of the class in which they are declared as intuitive.


To my knowledge, there are only historical reasons that
static variables of a class should not be defined inside
that class but instead declared inside and defined
outside of the class and in only one source file.

In order to fish or cut bait w.r.t. a proposal, I'd be interested in three things:
1. Are there any reasons against allowing the definition of constexpr static class members of the containing class type within this class itself?

Yes. The class is not yet completely defined at that point.
 
2. Are there any reasons against allowing the definition of (non-constexpr) static class members of the containing class type within this class as well?
3. From question 1 and 2 stems the question: Can we just allow static class members to be defined inside the class itself, as if they'd been defined outside of the class as inline variable?

Am I mistaken at some point?

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/285f811f-044a-4121-a107-c463bd0693e1%40isocpp.org.

Avi Kivity

unread,
May 2, 2017, 5:33:07 PM5/2/17
to std-pr...@isocpp.org, Richard Smith



On 05/02/2017 11:43 PM, Richard Smith wrote:
On 29 April 2017 at 14:51, Jakob Riedle <jakob....@gmail.com> wrote:
Am Mittwoch, 19. April 2017 18:45:15 UTC+2 schrieb HarD Gamer:

This basically represents a work-around but I hardly consider
inline variable definitions outside of the class in which they are declared as intuitive.


To my knowledge, there are only historical reasons that
static variables of a class should not be defined inside
that class but instead declared inside and defined
outside of the class and in only one source file.

In order to fish or cut bait w.r.t. a proposal, I'd be interested in three things:
1. Are there any reasons against allowing the definition of constexpr static class members of the containing class type within this class itself?

Yes. The class is not yet completely defined at that point.

Yet, we allow defining functions at that point, and constexpr static variables of the same type within the function (perhaps the distinction is the "historical reasons" you mentioned above).

 
2. Are there any reasons against allowing the definition of (non-constexpr) static class members of the containing class type within this class as well?
3. From question 1 and 2 stems the question: Can we just allow static class members to be defined inside the class itself, as if they'd been defined outside of the class as inline variable?

Am I mistaken at some point?

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/285f811f-044a-4121-a107-c463bd0693e1%40isocpp.org.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Jens Maurer

unread,
May 2, 2017, 6:10:38 PM5/2/17
to std-pr...@isocpp.org
On 05/02/2017 11:33 PM, Avi Kivity wrote:
>
>
> On 05/02/2017 11:43 PM, Richard Smith wrote:
>> On 29 April 2017 at 14:51, Jakob Riedle <jakob....@gmail.com <mailto:jakob....@gmail.com>> wrote:

>> In order to fish or cut bait w.r.t. a proposal, I'd be interested in three things:
>> 1. Are there any reasons against allowing the definition of *constexpr static class members *of the containing class type within this class itself?
>>
>>
>> Yes. The class is not yet completely defined at that point.
>
> Yet, we allow defining functions at that point, and constexpr static variables of the same type within the function (perhaps the distinction is the "historical reasons" you mentioned above).

Consider:

struct X {
static constexpr int n = 5;
int a[n]; // currently ok; useful
};

struct Y {
Y(int n) : n(n) { }
static constexpr Y y = 5;
int n;
int a[y.n]; // does this work?
};

struct Z {
Y(int n) : n(n) { }
static constexpr Z z = sizeof(Z);
int n;
int a[z.n]; // does this work?
};

Jens

Avi Kivity

unread,
May 2, 2017, 6:37:31 PM5/2/17
to std-pr...@isocpp.org, Jens Maurer


On 05/03/2017 01:10 AM, Jens Maurer wrote:
> On 05/02/2017 11:33 PM, Avi Kivity wrote:
>>
>> On 05/02/2017 11:43 PM, Richard Smith wrote:
>>> On 29 April 2017 at 14:51, Jakob Riedle <jakob....@gmail.com <mailto:jakob....@gmail.com>> wrote:
>>> In order to fish or cut bait w.r.t. a proposal, I'd be interested in three things:
>>> 1. Are there any reasons against allowing the definition of *constexpr static class members *of the containing class type within this class itself?
>>>
>>>
>>> Yes. The class is not yet completely defined at that point.
>> Yet, we allow defining functions at that point, and constexpr static variables of the same type within the function (perhaps the distinction is the "historical reasons" you mentioned above).
> Consider:
>
> struct X {
> static constexpr int n = 5;
> int a[n]; // currently ok; useful
> };
>
> struct Y {
> Y(int n) : n(n) { }
> static constexpr Y y = 5;
> int n;
> int a[y.n]; // does this work?
> };

Most likely, not.


But there are already such limitations:


constexpr int n0() { return 3; }


struct W {
static constexpr int n1() { return 5; }
int a0[n0()]; // works
int a1[n1()]; // error: fields must have a constant size?!
};

So we're already suffering from this when the definition of a function
is deferred.

Jens Maurer

unread,
May 4, 2017, 4:43:03 PM5/4/17
to std-pr...@isocpp.org
On 05/03/2017 12:37 AM, Avi Kivity wrote:
> On 05/03/2017 01:10 AM, Jens Maurer wrote:
>> struct Y {
>> Y(int n) : n(n) { }
>> static constexpr Y y = 5;
>> int n;
>> int a[y.n]; // does this work?
>> };
>
> Most likely, not.
>
>
> But there are already such limitations:
>
>
> constexpr int n0() { return 3; }
>
>
> struct W {
> static constexpr int n1() { return 5; }
> int a0[n0()]; // works
> int a1[n1()]; // error: fields must have a constant size?!
> };

Nobody has invested the time and energy to come up with
a revised set of rules how delayed-parsing of items showing
up in a class definition should be enhanced to allow some of
your/my examples, and expressly making ill-formed the others.

Papers welcome.

Jens

Reply all
Reply to author
Forward
0 new messages