virtual constexpr fields

696 views
Skip to first unread message

Botond Ballo

unread,
Mar 18, 2015, 4:25:51 PM3/18/15
to C++std-ext, eh...@mozilla.com, std-pr...@isocpp.org
There are cases where you would like to associate constants with a given type. Here is how you can currently do it in C++:

struct Merchandise {
    virtual int price() { return 0; }
};

struct Shoe : Merchandise {
    virtual int price() { return 10;
}

If you could do it this way instead:

struct Merchandise {
    virtual constexpr int price = 0;
};

struct Shoe : Merchandise {
    virtual constexpr int price = 10;
}

then the compiler could store the constant value directly in the vtable. This would eliminate the double indirection involved in dereferencing a function vtable entry, the cost of running that function at runtime, and the code size of the function in the compiled binary.

Virtual fields would be limited to being constexpr, so that the value to be placed in the vtable, like other values in the vtable, can be determined at compile time.

Has this, or something similar, ever been proposed? Is there any interest in it?

-- Botond and Ehsan

Gabriel Dos Reis

unread,
Mar 18, 2015, 4:41:53 PM3/18/15
to std-pr...@isocpp.org, C++std-ext, eh...@mozilla.com

Does the non-static data member need to be constexpr if it is virtual?  Why?

 

-- Gaby

--

---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

Tony Van Eerd

unread,
Mar 18, 2015, 4:53:05 PM3/18/15
to c++st...@accu.org, std-pr...@isocpp.org, eh...@mozilla.com

I would say it needs to be constexpr or static – at least for it to be stored in the vtable.

(ie assuming the vtable is shared by all instances of the class means that the value is shared by all instances of the class)

Ehsan Akhgari

unread,
Mar 18, 2015, 4:57:45 PM3/18/15
to Tony Van Eerd, c++st...@accu.org, std-pr...@isocpp.org
On Wed, Mar 18, 2015 at 4:52 PM, Tony Van Eerd <tvan...@blackberry.com> wrote:

I would say it needs to be constexpr or static – at least for it to be stored in the vtable.

(ie assuming the vtable is shared by all instances of the class means that the value is shared by all instances of the class)


Yes, exactly.  Note that from a pragmatic standpoint, it's probably important for compilers to be able to store the vtable in read-only memory in order to protect against security attacks attempting to overwrite vtable entries at runtime.



--
Ehsan

Gabriel Dos Reis

unread,
Mar 18, 2015, 5:27:33 PM3/18/15
to Tony Van Eerd, std-pr...@isocpp.org, c++st...@accu.org

If it is going in the vtable, why is it a *non-static* data member?


-- Gaby




From: Ehsan Akhgari <eh...@mozilla.com>
Sent: Wednesday, March 18, 2015 1:57 PM
To: Tony Van Eerd
Cc: c++st...@accu.org; std-pr...@isocpp.org
Subject: Re: [std-proposals] virtual constexpr fields
 

Bjarne Stroustrup

unread,
Mar 18, 2015, 5:43:16 PM3/18/15
to c++st...@accu.org, Tony Van Eerd, std-pr...@isocpp.org
(1) yes it should be immutable
(2) I described something like that in D&E (and maybe even in the ARM)
(3) what's the important use case?

Thiago Macieira

unread,
Mar 18, 2015, 5:49:56 PM3/18/15
to std-pr...@isocpp.org
On Wednesday 18 March 2015 21:27:23 Gabriel Dos Reis wrote:
> If it is going in the vtable, why is it a *non-static* data member?

It should be static.

This will be the first time we have a "virtual static" though.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358

Brian Bi

unread,
Mar 18, 2015, 5:53:09 PM3/18/15
to std-pr...@isocpp.org
operator new and operator delete are already implicitly virtual and static, aren't they?

--

---
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.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.



--
Brian Bi

Cassio Neri

unread,
Mar 18, 2015, 6:03:49 PM3/18/15
to c++st...@accu.org, Tony Van Eerd, std-pr...@isocpp.org

Zhihao Yuan

unread,
Mar 18, 2015, 6:20:23 PM3/18/15
to std-pr...@isocpp.org
On Wed, Mar 18, 2015 at 5:49 PM, Thiago Macieira <thi...@macieira.org> wrote:
> On Wednesday 18 March 2015 21:27:23 Gabriel Dos Reis wrote:
>> If it is going in the vtable, why is it a *non-static* data member?
>
> It should be static.
>

If it's static, it doesn't need to be virtual; if it's virtual, it
doesn't need to be static.

Use cases of static:
Base::var -- you already know the class name, what else you
expect?
void f() const { ... var } -- already most derived without virtual

Use cases of virtual:
ptr->var -- most derived
void f() const { ... var } -- works without static

--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
___________________________________________________
4BSD -- http://bit.ly/blog4bsd

ehsan....@gmail.com

unread,
Mar 18, 2015, 6:21:56 PM3/18/15
to std-pr...@isocpp.org, c++st...@accu.org, tvan...@blackberry.com, bja...@stroustrup.com
One use case is for projects that implement things such as custom RTTI.  For example, both LLVM and Mozilla have implemented their own custom RTTI that basically amounts to calling a virtual function that returns an identifier unique to the type.  It would be nice to be able to optimize this (which at least in the Mozilla code base is a pretty common code path) by eliminating the need to do a virtual call, and instead be able to extract this information directly from the vtable.

Cheers,
Ehsan

ehsan....@gmail.com

unread,
Mar 18, 2015, 6:25:08 PM3/18/15
to std-pr...@isocpp.org
On Wednesday, March 18, 2015 at 5:49:56 PM UTC-4, Thiago Macieira wrote:
On Wednesday 18 March 2015 21:27:23 Gabriel Dos Reis wrote:
> If it is going in the vtable, why is it a *non-static* data member?

It should be static.

Yes, we can make the syntax include the static keyword.
 
This will be the first time we have a "virtual static" though.

This was why we were hesitant to use the static keyword, but I don't feel strongly about this one way or the other.
 

Gabriel Dos Reis

unread,
Mar 18, 2015, 6:34:28 PM3/18/15
to std-pr...@isocpp.org, c++st...@accu.org, tvan...@blackberry.com, bja...@stroustrup.com

Immutable isn’t the same as ‘constexpr’ though.  You want immutable and statically initialized, and not a non-static data member – data that are shared across objects are “static”.

If I understand correctly, that would be the proper use of “static”: there is only one copy in the program.

 

-- Gaby

David Krauss

unread,
Mar 18, 2015, 7:03:35 PM3/18/15
to std-pr...@isocpp.org
On 2015–03–19, at 5:43 AM, Bjarne Stroustrup <bja...@stroustrup.com> wrote:

(3) what's the important use case?

Simple classification functions returning a single value, typically an enumerator, shouldn’t require an indirect branch. The other style for this is to use dynamic_cast, which also has too much overhead.


On 2015–03–19, at 6:20 AM, Zhihao Yuan <z...@miator.net> wrote:

If it's static, it doesn't need to be virtual; if it's virtual, it
doesn't need to be static.

It’s important to require the static keyword. Users need to know that it’s not an instance variable.


On 2015–03–19, at 4:25 AM, 'Botond Ballo' wrote:

Has this, or something similar, ever been proposed? Is there any interest in it?

It’s in my backlog of things to propose, although I’ve not done my homework to find precedents. Absolutely, go for it.


On 2015–03–19, at 5:53 AM, Brian Bi <bbi...@gmail.com> wrote:

operator new and operator delete are already implicitly virtual and static, aren't they?

Only operator delete. But that’s more a side-effect of the nature of a pointer to a destructed object. The would-be implicit parameter is converted to void* and given a name. Also, it’s not an ordinary virtual dispatch, but a static call from the most-derived destructor.

Nicol Bolas

unread,
Mar 18, 2015, 9:30:17 PM3/18/15
to std-pr...@isocpp.org, c++st...@accu.org, eh...@mozilla.com, botond...@yahoo.ca
Setting aside the bikeshed issue of what words to use to declare it,we first need to define what exactly it is. It's also important to remember that "vtables" don't exist. They're an implementation detail; no compiler is required to use them to make virtual functions/derived classes work.

So, you seem to be talking about an object who's storage is directly associated to a type. But, unlike static data members, every type derived from it will have separate storage. So "static" is the wrong word.

You want these values to be immutable. Once created, their value cannot be changed (and const-casting your way around it yields undefined behavior). So they're like a const variable.

While the object value is associated with the type, you want to access them as though they were a member of an instance of that type. And more to the point, you want the value returned to be the value fetched from the object associated with the object's dynamic type. Since a dynamic type is by definition a runtime fetch, it is certainly not "constexpr".

Each class needs to initialize this value with its own parameters. But this doesn't happen at construction time; it happens somewhere else. Possibly before the execution of main(). Which means that it's like a static in terms of initialization and destruction.

I don't know. This is a whole lot of complexity just to do cheaper RTTI. Wouldn't it make more sense to just add cheaper RTTI to C++?

Bjarne Stroustrup

unread,
Mar 18, 2015, 9:37:04 PM3/18/15
to c++st...@accu.org, std-pr...@isocpp.org, eh...@mozilla.com, botond...@yahoo.ca


On 3/18/2015 9:30 PM, Nicol Bolas wrote:
>
>
> I don't know. This is a whole lot of complexity just to do cheaper
> RTTI. Wouldn't it make more sense to just add cheaper RTTI to C++?

Such as?

Bjarne Stroustrup

unread,
Mar 18, 2015, 9:41:38 PM3/18/15
to c++st...@accu.org, std-pr...@isocpp.org, eh...@mozilla.com, botond...@yahoo.ca


On 3/18/2015 9:30 PM, Nicol Bolas wrote:
>
>
> I don't know. This is a whole lot of complexity just to do cheaper
> RTTI. Wouldn't it make more sense to just add cheaper RTTI to C++?

Such as?

Nevin Liber

unread,
Mar 18, 2015, 9:50:12 PM3/18/15
to std-pr...@isocpp.org
On 18 March 2015 at 20:30, Nicol Bolas <jmck...@gmail.com> wrote:
This is a whole lot of complexity just to do cheaper RTTI.

While I see a vocabulary problem (given that this is something new, it isn't necessarily unusual), I don't see a complexity problem.  What difficulties do you envision to implement it?  What difficulties do you envision to use it?

Personally, I'd like to see more motivating examples, as well as limitations.  For instance:  can you store a std::string in the vtable (or equivalent)?
-- 
 Nevin ":-)" Liber  <mailto:ne...@eviloverlord.com(847) 691-1404

David Krauss

unread,
Mar 18, 2015, 9:56:34 PM3/18/15
to std-pr...@isocpp.org, c++st...@accu.org, eh...@mozilla.com, botond...@yahoo.ca
On 2015–03–19, at 9:30 AM, Nicol Bolas <jmck...@gmail.com> wrote:

Setting aside the bikeshed issue of what words to use to declare it,we first need to define what exactly it is. It's also important to remember that "vtables" don't exist. They're an implementation detail; no compiler is required to use them to make virtual functions/derived classes work.

So, you seem to be talking about an object who's storage is directly associated to a type. But, unlike static data members, every type derived from it will have separate storage. So "static" is the wrong word.

This thread hasn’t actually agreed that, yet. There are two other alternatives:

1. Let the name of the virtual object be an rvalue, like an enumerator, so it has no apparent storage. Note that these values will often have enumeration type.

2. Stick an object pointer in the vtable (or whatever other sort of dispatch system), which refers to an object shared between types of a hierarchy.

Anyway, behavior can be defined however works best, even if the static keyword gains yet another nuance.

While the object value is associated with the type, you want to access them as though they were a member of an instance of that type. And more to the point, you want the value returned to be the value fetched from the object associated with the object's dynamic type. Since a dynamic type is by definition a runtime fetch, it is certainly not "constexpr”.

There are already rumblings about enabling dynamic types in constant expression evaluation. In principle, RTTI is no more dynamic than any other part of an object. The restriction on literal types is arbitrary.

Each class needs to initialize this value with its own parameters. But this doesn't happen at construction time; it happens somewhere else. Possibly before the execution of main(). Which means that it's like a static in terms of initialization and destruction.

It’s statically initialized.

I don't know. This is a whole lot of complexity just to do cheaper RTTI. Wouldn't it make more sense to just add cheaper RTTI to C++?

You raise a good question regarding object identity, but there’s no complexity there. The proposal is essentially to allow arbitrary literal types where we currently have only function pointers. It’s nowhere near a redesign of RTTI.

Thiago Macieira

unread,
Mar 19, 2015, 12:55:43 AM3/19/15
to std-pr...@isocpp.org
On Wednesday 18 March 2015 20:49:28 Nevin Liber wrote:
> Personally, I'd like to see more motivating examples, as well as
> limitations. For instance: can you store a std::string in the vtable (or
> equivalent)?

That's where the constexpr keyword comes into play: you should be able to
store anything that is a literal type.

std::string is not a literal type.

David Krauss

unread,
Mar 19, 2015, 1:20:37 AM3/19/15
to std-pr...@isocpp.org

On 2015–03–19, at 12:55 PM, Thiago Macieira <thi...@macieira.org> wrote:

That's where the constexpr keyword comes into play: you should be able to
store anything that is a literal type.

std::string is not a literal type.

std::string & works, though.

struct s {
    static std::string kind_str;
    static constexpr virtual
        std::string & kind = kind_str; // provides read-write access
};

The rules for constexpr references are inconsistent. You can bind them to temporaries, provided the temporary is of literal type, but for e.g. std::string there must be a named object. Such references aren’t always even compile-time constants. See also http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2005 . (Unfortunately I didn’t attend the discussion where it was closed, and I’m not sure the point of the DR submission came across.)

Perhaps the strict constexpr requirement can be dropped, but require overrides to match in constexpr-ness. Then implementations can add a level of indirection for the non-constant case, essentially automating the above trick.

Douglas Boffey

unread,
Mar 19, 2015, 6:30:20 AM3/19/15
to std-pr...@isocpp.org, c++st...@accu.org, eh...@mozilla.com, botond...@yahoo.ca
Althougn not compelling, as the virtual constexprs would normally only be used twice, one example of where they could be useful is in service dispatching, eg:
 
 
using Protocol = /* whatever */;     
     
class Handler {     
public:     
virtual constexpr Protocol low; // see note (1)     
virtual constexpr Protocol high; // see note (1)     
virtual void handle(Protocol protocol, Payload payload) = 0;     
// …     
};     
     
class Dispatcher {     
public:     
void register(Handler *handler);     
void deregister(Handler *handler);     
// …     
};

 
In this case, the register and deregister methods would both use handler->high and handler->low.
---
Note (1) This example illustrates one conflict of notation.  I would like low & high to be pure virtual, but using ‘= 0’ would presumably give high & low the values 0.  Thus, I have left the values undefined in the example.

Matthew Woehlke

unread,
Mar 19, 2015, 10:23:26 AM3/19/15
to std-pr...@isocpp.org
On 2015-03-18 17:27, Gabriel Dos Reis wrote:
> If it is going in the vtable, why is it a *non-static* data member?

At present, virtual and static are rather orthogonal concepts, i.e. you
*can't have* a virtual static member. In particular, if you have a A*
and you call a static method "on" it, you will always get the member of
A, even if the object is really a B* and B has a same-named member. In
the case that the proposal aims to support, this is NOT the case; you'd
get the member from B.

That said, it seems likely to be useful to be able to access the
constant value without a class instance. However, that's achievable
without the virtual itself being static:

struct A
{
constexpr static auto StaticType = 10;
constexpr virtual type = StaticType;
}

(...and I could argue that this makes for better code style, as it is
explicit when you're using the static value and when you're using the
instance virtual value.)

It's also worth noting that the only practical difference between a
constexpr static and a (proposed) constexpr virtual is that the latter
presumably requires a class instance to access; it's immutable in both
cases.

Incidentally, a proposal should probably note that this is already
partly achievable by having a non-virtual const member on the base class
with a protected ctor that derived classes use to provide their own
value for the same. I can think of at least a couple reasons offhand why
this is an inferior approach compared to the proposal, but I shall leave
enumeration of the same as an exercise for the proposal writer :-).

--
Matthew

Thiago Macieira

unread,
Mar 19, 2015, 10:32:54 AM3/19/15
to std-pr...@isocpp.org
On Thursday 19 March 2015 13:20:19 David Krauss wrote:
> > On 2015–03–19, at 12:55 PM, Thiago Macieira <thi...@macieira.org> wrote:
> >
> > That's where the constexpr keyword comes into play: you should be able to
> > store anything that is a literal type.
> >
> > std::string is not a literal type.
>
> std::string & works, though.
>
> struct s {
> static std::string kind_str;
> static constexpr virtual
> std::string & kind = kind_str; // provides read-write access
> };

Sure, it initialises a reference, but it's referencing a type that may not
have been initialised yet or may have already been destroyed.

> The rules for constexpr references are inconsistent. You can bind them to
> temporaries, provided the temporary is of literal type, but for e.g.
> std::string there must be a named object. Such references aren’t always
> even compile-time constants. See also
> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2005 .
> (Unfortunately I didn’t attend the discussion where it was closed, and I’m
> not sure the point of the DR submission came across.)
>
> Perhaps the strict constexpr requirement can be dropped, but require
> overrides to match in constexpr-ness. Then implementations can add a level
> of indirection for the non-constant case, essentially automating the above
> trick.

Matthew Woehlke

unread,
Mar 19, 2015, 10:46:38 AM3/19/15
to std-pr...@isocpp.org
On 2015-03-18 21:30, Nicol Bolas wrote:
> You want these values to be immutable. Once created, their value cannot be
> changed (and const-casting your way around it yields undefined behavior).
> So they're like a const variable.
>
> [...] And more to the point, you want the value returned to be the
> value fetched from the object associated with the object's dynamic
> type. Since a dynamic type is by definition a runtime fetch, it is
> certainly not "constexpr".

Except that a qualified member access *is* constexpr. Also I think the
point is partly an implicit requirement that the compiler is able to
determine the qualified value at compile time (which is necessary of
course to be able to write the constructed value into the vtable). For
similar reasons, such member may not be of a non-constexpr type.

And... on further thought I'm just going to flat out disagree. The
member itself is constexpr. Runtime access of the member on a runtime
instance is not, of course, but if you think about it, that's not really
different from calling a constexpr function at runtime. Doing so does
not make such a function "certainly not constexpr".

On the other hand, if you have a *compile time* instance of a class with
a constexpr virtual data member, I'd expect that to work *at compile
time*... ergo, it is indeed constexpr.

> While the object value is associated with the type, you want to access them
> as though they were a member of an instance of that type.

True, but the compiler should be able to handle this easily; it's very
similar to taking the address of a virtual member function. A virtual
member function is similarly a function associated with the type, but
accessed as though a member of an instance.

> I don't know. This is a whole lot of complexity just to do cheaper RTTI.
> Wouldn't it make more sense to just add cheaper RTTI to C++?

I wouldn't say "just"... while that is *an* obvious use case, I'm not
convinced it is the only one. For example:

class Creature
{
public:
constexpr virtual double base_hp = nullptr;
constexpr virtual double movement_rate = nullptr;
// etc.
}

(Which brings up another point; are pure virtuals allowed? If yes, how
are they declared, considering that '0' may be a legal value? I used
'nullptr' above, but this is another potential bikeshed discussion.)

--
Matthew

jgot...@gmail.com

unread,
Mar 20, 2015, 9:39:27 PM3/20/15
to std-pr...@isocpp.org, c++st...@accu.org, eh...@mozilla.com, botond...@yahoo.ca
Another, possibly simpler way of achieving the same effect is to weaken the rule that virtual functions can't be constexpr.  If we say that final virtual functions can be final, then we can define Shoe::price as


struct Shoe : Merchandise {
   
constexpr int price() override final { return 10;
}

This would be perfectly safe, because the compiler could always compute Shoe::price() without having to look at a vtable.

Joe Gottman

Douglas Boffey

unread,
Mar 21, 2015, 2:34:41 AM3/21/15
to std-pr...@isocpp.org, c++st...@accu.org, eh...@mozilla.com, botond...@yahoo.ca
That doesn't fit the bill, as the OP would want to get the value from
a base class pointer/reference.

On 3/21/15, jgot...@gmail.com <jgot...@gmail.com> wrote:
> Another, possibly simpler way of achieving the same effect is to weaken the
>
> rule that virtual functions can't be constexpr. If we say that *final
> *virtual

Thiago Macieira

unread,
Mar 21, 2015, 5:09:17 PM3/21/15
to std-pr...@isocpp.org
On Friday 20 March 2015 18:39:26 jgot...@gmail.com wrote:
> Another, possibly simpler way of achieving the same effect is to weaken the
> rule that virtual functions can't be constexpr. If we say that *final
> *virtual functions can be final, then we can define Shoe::price as
>
>
> struct Shoe : Merchandise {
> constexpr int price() override final { return 10;
> }
>
> This would be perfectly safe, because the compiler could always compute
> Shoe::price() without having to look at a vtable.

The whole point is that it shouldn't be final.

struct FancyShoe : Shoe {
constexpr int price() override { return 20; }
};

Myriachan

unread,
Mar 23, 2015, 5:30:33 PM3/23/15
to std-pr...@isocpp.org
I've wanted a "static virtual" concept just for convenience reasons to solve similar problems.  The point would just be to avoid having to have a secondary static function.

enum class Type : int
{
    SHOE
,
};

struct Merchandise
{
   
virtual Type GetType() const = 0;
};

struct Shoe : public Merchandise
{
   
static virtual Type GetType() const override { return Type::SHOE; }
};

Type type1 = Shoe().GetType();
Type type2 = Shoe::GetType();
assert(type1 == type2);

One possible implementation would be to still be a "thiscall" function, whatever that means to the implementation, but ignoring the "this" parameter.  Shoe::GetType() could then pass nullptr as this.  Another possible implementation is to emit two functions of different mangled names, one static and one virtual.  Either implementation would work fine.

Rules as I imagine them:

1. Destructors can't be static virtual.
2. static virtual functions cannot reference this.  (obvious)
3. The static attribute is not heritable: a non-static virtual function may override a static virtual function.

Possible solutions to the function pointer problem:
4a. It is not possible to get a non-member pointer to a static virtual function.
--or--
4b. Ampersand-prefixed member pointer expressions (I don't remember their formal name)--i.e., &Shoe::GetType--would disambiguate member function pointer and non-member function pointer by context, like occurs for overloaded functions.

Melissa

wka...@yahoo.com

unread,
Feb 18, 2016, 5:45:59 PM2/18/16
to ISO C++ Standard - Future Proposals, c++st...@accu.org, eh...@mozilla.com, botond...@yahoo.ca
Is it a viable alternative to just drop the rule that constexpr functions cannot be virtual, and add a rule that constexpr virtual functions cannot have parameters?  This would permit the compiler to store a constant in the vtable rather than a function address.  Would this cause too many corner cases for member function pointers?

Gabriel Dos Reis

unread,
Feb 18, 2016, 6:01:52 PM2/18/16
to std-pr...@isocpp.org, c++st...@accu.org, eh...@mozilla.com, botond...@yahoo.ca

The real reason I put that restriction in there in the first place was because people were still not comfortable with the idea that a compiler could run a function at compile-time.  So, we wanted to make it as simple and as concrete as possible – just to deal with the various FUD being thrown around 10 years ago.

 

The simplest (and correct, IMO) fix is to remove that restriction.  We already require compilers to track object’s dynamic type when doing constexpr evaluation.  Please, don’t replace that restriction with another restriction.  We’ve learned the value of constexpr for the last 10 years and we are now all conformable with the notion.

 

I am not expressing opinion about the ‘virtual fields’ themselves (which I must have heard of for the umpteenth time now, since at least 1995.)

 

-- Gaby

 

--


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

David Krauss

unread,
Feb 18, 2016, 9:59:15 PM2/18/16
to ISO C++ Standard - Future Proposals
All, please take care when using reply-all in this thread. It’s getting cross-posted to the internal reflector.


On 2016–02–19, at 6:45 AM, wkaras via ISO C++ Standard - Future Proposals <std-pr...@isocpp.org> wrote:

Is it a viable alternative to just drop the rule that constexpr functions cannot be virtual, and add a rule that constexpr virtual functions cannot have parameters?  This would permit the compiler to store a constant in the vtable rather than a function address.  Would this cause too many corner cases for member function pointers?

The result of that function call would be a prvalue, which is a suboptimal way to access the externally-linked object which would implement a virtual field.

Also, a constexpr function doesn’t always have to produce a constant. Given a member function, the standard only asks that some input parameter values result in successful constant evaluation, no diagnostic required. If it’s a member of a class template, that’s loosened to some combination of template and function parameters. 

Virtual fields would behave like constexpr objects, not functions.

ytq...@gmail.com

unread,
Feb 19, 2016, 1:22:52 AM2/19/16
to ISO C++ Standard - Future Proposals

A point to perhaps consider is an analogy to virtual base classes.  The classic example is where D inherits from B and C, all of which inherit virtually from A.  But B and C, rather than inheriting virtually from A, could simply (both) have a virtual member function that returns a pointer to A.  D could override these virtual member functions, returning its this pointer (implicitly cast to A *).  It seems a similar trade off.  You eliminate the need for a somewhat pesky language feature that is not so frequently used.  The price is the overhead of a function call that is not needed with the pesky feature (plus the bother of having to do overrides of A member functions in D that could have been done in B or C).

alan.d...@gmail.com

unread,
May 17, 2017, 7:48:24 PM5/17/17
to ISO C++ Standard - Future Proposals, c++st...@accu.org, tvan...@blackberry.com, bja...@stroustrup.com
I know this is an old thread, but I've got one use case. I've got a hierarchy of classes that makes use of several small arrays in a member function. Each class has its own set of sizes for the arrays, but the method is still the same regardless of the size of the arrays. I know using templates would be one solution, but the template parameters are not known until run time, and it's annoying to change function signatures to accept templated objects. I'm also working with CUDA and I want to avoid dynamically allocating memory for small arrays.

class Parent
{
public:
     __host__ __device__ void CalculateSomething(someParams)
    {
        std::size_t s = GetArraySize();
        double array1[s];
        double array2[s+1];
        double array3[OtherConstexprFunction(s)];

        // do stuff with arrays
    }

protected:
    __host__ __device__ virtual constexpr std::size_t GetArraySize() = 0;
};

class Child1
{
protected:
    __host__ __device__ virtual constexpr std::size_t GetArraySize() { return 1; }
};

class Child2
{
protected:
    __host__ __device__ virtual constexpr std::size_t GetArraySize() { return 2; }
};

Here's the template version:
class C
public:
    template<std::size_t N>
     __host__ __device__ void CalculateSomething(someParams)
    {
        double array1[N];
        double array2[N+1]; // I don't think this or the next line will compile even if they could be constexpr functions because the template parameter is not known until runtime
        double array3[OtherFunction(N)];

        // do stuff with arrays
    }
};

I'm sure I could also do some unclear tricks with macros, but that also seems like a hassle. If you know of a better solution, let me know. But it seems like this could be a good use case for constexpr members.

- Alan

On Wednesday, March 18, 2015 at 2:43:16 PM UTC-7, Bjarne Stroustrup wrote:
(1) yes it should be immutable
(2) I described something like that in D&E (and maybe even in the ARM)
(3) what's the important use case?

On 3/18/2015 4:57 PM, Ehsan Akhgari wrote:
On Wed, Mar 18, 2015 at 4:52 PM, Tony Van Eerd <tvan...@blackberry.com> wrote:

I would say it needs to be constexpr or static – at least for it to be stored in the vtable.

(ie assuming the vtable is shared by all instances of the class means that the value is shared by all instances of the class)


Yes, exactly.  Note that from a pragmatic standpoint, it's probably important for compilers to be able to store the vtable in read-only memory in order to protect against security attacks attempting to overwrite vtable entries at runtime.
 

From: Gabriel Dos Reis [mailto:g...@microsoft.com]
Sent: Wednesday, March 18, 2015 4:42 PM
To: 'std-pr...@isocpp.org'; C++std-ext; eh...@mozilla.com
Subject: [c++std-ext-16622] Re: [std-proposals] virtual constexpr fields

 

Does the non-static data member need to be constexpr if it is virtual?  Why?

 

-- Gaby

 

From: 'Botond Ballo' via ISO C++ Standard - Future Proposals [mailto:std...@isocpp.org]
Sent: Wednesday, March 18, 2015 1:26 PM
To: C++std-ext; eh...@mozilla.com; ...@isocpp.org
Subject: [std-proposals] virtual constexpr fields

 

There are cases where you would like to associate constants with a given type. Here is how you can currently do it in C++:



struct Merchandise {
    virtual int price() { return 0; }
};

struct Shoe : Merchandise {
    virtual int price() { return 10;
}

If you could do it this way instead:

struct Merchandise {
    virtual constexpr int price = 0;
};

struct Shoe : Merchandise {
    virtual constexpr int price = 10;
}

then the compiler could store the constant value directly in the vtable. This would eliminate the double indirection involved in dereferencing a function vtable entry, the cost of running that function at runtime, and the code size of the function in the compiled binary.

Virtual fields would be limited to being constexpr, so that the value to be placed in the vtable, like other values in the vtable, can be determined at compile time.

Has this, or something similar, ever been proposed? Is there any interest in it?

-- Botond and Ehsan

 

--


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

Thiago Macieira

unread,
May 17, 2017, 11:20:01 PM5/17/17
to std-pr...@isocpp.org
On Wednesday, 17 May 2017 16:48:24 PDT alan.d...@gmail.com wrote:
> double array2[N+1]; // I don't think this or the next line will
> compile even if they could be constexpr functions because the template
> parameter is not known until runtime

Template parameters are ALWAYS known at compile time.

p_ha...@wargaming.net

unread,
May 18, 2017, 8:29:57 PM5/18/17
to ISO C++ Standard - Future Proposals, c++st...@accu.org, tvan...@blackberry.com, bja...@stroustrup.com, alan.d...@gmail.com, swa...@gmail.com, roberto...@gmail.com

On Thursday, May 18, 2017 at 9:48:24 AM UTC+10, alan.d...@gmail.com wrote:
I know this is an old thread, but I've got one use case. 

Since this thread's come alive, this would possibly also resolve the initial motivating use-case for p0130r0: Comparing Virtual Methods, effectively bringing the 'fast' example into the virtual interfaces system.

alan.d...@gmail.com

unread,
May 19, 2017, 2:15:33 PM5/19/17
to ISO C++ Standard - Future Proposals
Thiago, what I meant to say is that I am accepting command line input from a user and I can't use that to instantiate a template.

Thiago Macieira

unread,
May 19, 2017, 4:27:40 PM5/19/17
to std-pr...@isocpp.org
On sexta-feira, 19 de maio de 2017 11:15:33 PDT alan.d...@gmail.com wrote:
> Thiago, what I meant to say is that I am accepting command line input from a
> user and I can't use that to instantiate a template.

Then it's not obvious what you're trying to do.

Please send an example that doesn't require C++ extensions that others may not
be familiar with.

Nicol Bolas

unread,
May 19, 2017, 4:52:30 PM5/19/17
to ISO C++ Standard - Future Proposals, alan.d...@gmail.com
On Friday, May 19, 2017 at 2:15:33 PM UTC-4, alan.d...@gmail.com wrote:
Thiago, what I meant to say is that I am accepting command line input from a user and I can't use that to instantiate a template.

... that's not possible. That's not going to be possible.

Command line input, by definition happens at runtime. Template instantiate happens at compile time. You cannot use a runtime value to do compile-time things. You're trying to use the wrong tool for the job.

Paul Hampson

unread,
May 20, 2017, 4:44:27 AM5/20/17
to ISO C++ Standard - Future Proposals, alan.d...@gmail.com
On Saturday, 20 May 2017 04:15:33 UTC+10, alan.d...@gmail.com wrote:
Thiago, what I meant to say is that I am accepting command line input from a user and I can't use that to instantiate a template.

If I'm reading your code example correctly, what you're trying to do is have the method defined in the parent class be compiled differently (different sized local arrays) depending on which derived class it's being called via. The user input selects the derived class, it doesn't specify the array-size *directly*.

Since the 'do stuff with arrays' doesn't change based on array size, I think what you actually want is the code that creates those arrays on the stack to be in an overriding virtual method in each derived class (pure-virtual in the base class), which can call common 'do stuff with arrays' with decayed pointers to the arrays, and possibly the size if needed.

Your compiler might even be able to do nice things with devirtualisation and inlining there, if you're lucky, which'd produce basically exactly the code you're trying to get here already.

Then you don't need the extension here, because the overriding method would either have the size inline or it'd be a static constexpr class member for the derived class.

alan.d...@gmail.com

unread,
May 23, 2017, 8:18:01 PM5/23/17
to ISO C++ Standard - Future Proposals
Paul, that is a great solution! I agree now that virtual constexpr members are not needed. I was able to use templates to solve the problem as well, though I like your solution better.

class MyClass
{
public:
void Calculate(std::size_t orderOfMethod, otherParams)
{
switch(orderOfMethod)
{
case 0:
Calculate<0>(otherParams);
break;
case 1:
Calculate<1>(otherParams);
break;
...
}


template<std::size_t N>
void Calculate(otherParams)
{
double array1[N+1];
double array2[someConstexprFunction(N)];

//do stuff with arrays
}
};

This is not unreasonable because there are currently only 6 cases and it is unlikely that any others will be added.

Reply all
Reply to author
Forward
0 new messages