Can virtual functions be constexpr?
Asked Answered
E

4

43

Can virtual functions like X::f() in the following code

struct X 
{
    constexpr virtual int f() const 
    {
        return 0;
    }
};

be constexpr?

Eliathas answered 16/1, 2016 at 14:34 Comment(5)
Think about it a minute. It would completely defeat the constexpr purpose.Tisman
Such a hypothetical function could be used as a constant expression only if the complete type of the calling instance is known to be X. This would essentially require the language to specify "devirtualization rules".Fleabag
@πάνταῥεῖ In D you can do compile time function evaluation with virtual functions. So it's not unthinkable.Eliathas
Well, I think it would make sense at least for final functions to be able to be constexpr.Wormeaten
Not just for final methods. It could be useful for a compile time unit test. You instantiate a derived class on the stack and use a static_assert on the result of a virtual method. At that point the whole function body could be visible to the compiler.Protrude
R
38

Up through C++17, virtual functions could not be declared constexpr. The general reason being that, in constexpr code, everything happen can at compile time. So there really isn't much point to having a function which takes a reference to a base class and calls virtual functions on it; you may as well make it a template function and pass the real type, since you know the real type.

Of course, this thinking doesn't really work as constexpr code becomes more complex, or if you want to share interfaces between compile-time and runtime code. In both cases, losing track of the original type is easy to do. It would also allow std::error_code to be more constexpr-friendly.

Also, the fact that C++20 will allow us to do (limited) dynamic allocation of objects means that it is very easy to lose track of the original type. You can now create a vector<Base*> in constexpr code, insert some Derived class instances into it, and pass that to a constexpr function to operate on.

So C++20 allows virtual functions to be declared constexpr.

Reinsure answered 3/5, 2019 at 15:5 Comment(3)
Ooh, interesting; I actually just ran into a case where compile-time polymorphism would be really useful yesterday, while attempting to set up a compile-time tag list of potentially variable length to aid with other compile-time tasks. Using a const reference to an empty base to allow array size to be a NTTP on the actual tag list was a relatively clean way to solve one of the issues, but introduced its own problems due to the lack of constexpr virtual. Glad to see this'll be available soon!Heteronym
@JustinTime NTTP?Vanburen
@curiousguy: Non-type template parameter.Reinsure
F
39

This answer is no longer correct as of C++20.

No. From [dcl.constexpr]/3 (7.1.5, "The constexpr specifier"):

The definition of a constexpr function shall satisfy the following requirements:

— it shall not be virtual

Fleabag answered 16/1, 2016 at 14:36 Comment(7)
It is weird, for gcc version 4.9.2 20141101 (Red Hat 4.9.2-1) (GCC) it worksKnowhow
@zaratustra: And GCC 6 doesn't :-(Fleabag
What is the rationale.Formate
@CiroSantilli华涌低端人口六四事件法轮功: "virtual" means "at runtime". "constexpr" means "at compile time".Fleabag
polymorphic constexpr object with its state could be determined at compile timeArchaeological
Note that virtual constexpr will be legal in c++20. see en.cppreference.com/w/cpp/language/constexprOstracism
Could you please explain the reason behind this prohibition?Wheeled
R
38

Up through C++17, virtual functions could not be declared constexpr. The general reason being that, in constexpr code, everything happen can at compile time. So there really isn't much point to having a function which takes a reference to a base class and calls virtual functions on it; you may as well make it a template function and pass the real type, since you know the real type.

Of course, this thinking doesn't really work as constexpr code becomes more complex, or if you want to share interfaces between compile-time and runtime code. In both cases, losing track of the original type is easy to do. It would also allow std::error_code to be more constexpr-friendly.

Also, the fact that C++20 will allow us to do (limited) dynamic allocation of objects means that it is very easy to lose track of the original type. You can now create a vector<Base*> in constexpr code, insert some Derived class instances into it, and pass that to a constexpr function to operate on.

So C++20 allows virtual functions to be declared constexpr.

Reinsure answered 3/5, 2019 at 15:5 Comment(3)
Ooh, interesting; I actually just ran into a case where compile-time polymorphism would be really useful yesterday, while attempting to set up a compile-time tag list of potentially variable length to aid with other compile-time tasks. Using a const reference to an empty base to allow array size to be a NTTP on the actual tag list was a relatively clean way to solve one of the issues, but introduced its own problems due to the lack of constexpr virtual. Glad to see this'll be available soon!Heteronym
@JustinTime NTTP?Vanburen
@curiousguy: Non-type template parameter.Reinsure
Y
20

Can virtual functions be constexpr?

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

Yclept answered 28/7, 2020 at 9:20 Comment(0)
O
2

In C++20 and later, a constexpr function can be virtual, and a constructor can be defined as constexpr when the enclosing class has any virtual base classes.

Obrian answered 5/3, 2024 at 14:4 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.