Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

constexpr and virtual

Tags:

c++

c++11

I've been thinking why constexr and virtual are mutually exclusive, and someone added:

... constexpr is all about execution at compile time; if we're executing the function at compile time, we obviously know the type of data upon which it's acting at compile time as well, so late binding clearly isn't relevant.

However, it's possible that the dynamic type is not identical to the static type even in compile-time, and there might be cases where the dynamic type is needed:

class A {
public:
    /* virtual */ constexpr int foo() {
        return 1;
    }
};

class B : public A {
public:
    constexpr int foo() {
        return 2;
    }
};

constexpr int foo(A &a) {
    // The static type is fixed here.
    // What if we want to call B::foo() ?
    return a.foo();
}

int main() {
    B b;
    constexpr int c = foo(b);
    return 0;
}

That is, my question is

  • what's the (possible) rationale behind the standard prohibiting the combination of the two?
like image 938
b1sub Avatar asked Nov 14 '17 05:11

b1sub


People also ask

Can constexpr functions be virtual?

Can virtual functions be constexpr? Yes. Only since C++20, virtual functions can be constexpr .

What does constexpr mean?

constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time. A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations.

Does constexpr improve performance?

In Conclusion. constexpr is an effective tool for ensuring compile-time evaluation of function calls, objects and variables. Compile-time evaluation of expressions often leads to more efficient code and enables the compiler to store the result in the system's ROM.

Should I use constexpr everywhere?

Yes. I believe putting such const ness is always a good practice wherever you can. For example in your class if a given method is not modifying any member then you always tend to put a const keyword in the end.


3 Answers

This restriction exists since constexpr was introduced in C++11:

10.1.5 The constexpr specifier [dcl.constexpr]

3 The definition of a constexpr function shall satisfy the following requirements:
(3.1) - it shall not be virtual;


But you're asking about rationale for this restriction, and not about the restriction itself.

The fact is, it may just be an oversight. Since in a constant expression the dynamic type of the object is required to be known, this restriction is unnecessary and artificial: This is what Peter Dimov and Vassil Vassilev assert in P1064R0, where they propose to remove it.

In fact, the wording for it no longer exists in the current draft.

like image 141
Cássio Renan Avatar answered Oct 18 '22 14:10

Cássio Renan


Because virtual calls are resolved via vtables/RTTI (RunTime Type Information) located in the memory layout of your object at runtime, the "true type" behind the "used object handle" is not known at compile time.

In your example:

constexpr int foo(A &a) {
    // The static type is fixed here.
    // What if we want to call B::foo() ?
    return a.foo();
}

If the foo member function is virtual there is no way for that foo function to be executed at compile time. And there is no point in marking a function as constexpr if it can never be executed at compile time. Hence there is no point in ever marking something both constexpr and virtual.


Now technically, depending on the code complexity, multiple cases might be resolvable by adding a completely new system (other than RTTI) to resolve virtual calls that would be compile time compatible (e.g some form of compiler meta data when everything is constexpr that remembers what type of instance you put in a pointer/reference) but that simply is not a thing right now.

If you want a runtime indirection (which is what virtual does) it doesn't make much sense to also want that to be executed at compile time.

P.S: sorry for the "compile time" and "runtime" spam.

like image 22
Drax Avatar answered Oct 18 '22 14:10

Drax


Indeed, it is possible for compilers to know at compile time what is the dynamic type of a constant expression. This is a possibility, that is some time used by optimizer to devirtualize calls at compile time.

But the c++ language evolution take also in consideration how difficult it is to implement it in compilers. If such a consideration were not taken, then the c++ standard will be too far from the c++ coded so that it would be unusefull.

Maybe, it has been evaluated that keeping trac of the static type of every reference during constant expression evaluation would be too expensive to implement. This is where reality hurts!

like image 37
Oliv Avatar answered Oct 18 '22 13:10

Oliv