虚函数可以是constexpr吗?

42

以下代码中的虚函数 X::f() 是否可以被调用?

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

如何成为constexpr


3
想一想,这将完全违背 constexpr 的目的。 - πάντα ῥεῖ
如果调用实例的完整类型已知为 X,则这样的假设函数只能用作常量表达式。这基本上需要语言指定“去虚拟化规则”。 - Kerrek SB
2
@πάνταῥεῖ 在D语言中,你可以使用虚函数进行编译时函数评估。因此这并非不可想象的事情。 - Ralph Tandetzky
2
我认为至少对于“final”函数来说,能够成为“constexpr”是有意义的。 - JohnB
1
不仅适用于final方法。它也可以用于编译时单元测试。您可以在堆栈上实例化一个派生类,并对虚方法的结果使用static_assert。此时,整个函数体可能对编译器可见。 - QBziZ
3个回答

37

截至C++20,此答案已不再正确。

不可以。根据[dcl.constexpr]/3 (7.1.5, "The constexpr specifier")的规定:

constexpr函数的定义应满足以下要求:

— 不能是虚函数


1
很奇怪,对于 gcc version 4.9.2 20141101 (Red Hat 4.9.2-1) (GCC) 它可以工作 - neshkeev
3
@zaratustra说:"连GCC 6都不支持",附带了一个链接。 - Kerrek SB
什么是基本原理。 - Ciro Santilli OurBigBook.com
3
可以在编译时确定其状态的多态constexpr对象。 - Sergei Krivonos
8
请注意,在C++20中,“virtual constexpr”将是合法的。请参阅https://en.cppreference.com/w/cpp/language/constexpr。 - Yanis.F
请问您能否解释一下这个禁令背后的原因? - Caglayan DOKME

33
到C++17为止,virtual函数无法被声明为constexpr。一般来说,这是因为在constexpr代码中,所有的操作都必须在编译时完成。因此,在一个函数中传递一个基类的引用并调用其中的virtual函数并没有太多意义;你可以将其定义为一个template函数并传递真实类型,因为你知道真实类型。

当然,随着constexpr代码变得越来越复杂,或者你希望在编译时和运行时之间共享接口时,这种思路就不再适用了。在这两种情况下,很容易失去原始类型的跟踪。这也将使std::error_code更加友好。

此外,C++20允许我们进行(有限的)动态对象分配,这意味着很容易失去原始类型的跟踪。现在,您可以在constexpr代码中创建一个vector<Base*>,将一些Derived类的实例插入其中,并将其传递给constexpr函数进行操作。

因此,C++20 允许声明virtual函数为constexpr


哦,有趣;昨天我遇到了一个情况,编译时多态将非常有用,当我试图设置一个可能具有可变长度的编译时标记列表以帮助其他编译时任务时。使用对空基类的const引用允许数组大小成为实际标记列表上的NTTP是相对清晰的解决方法之一,但由于缺少constexpr virtual而引入了自己的问题。很高兴看到这很快就会推出! - Justin Time - Reinstate Monica
@JustinTime NTTP? - curiousguy
1
@curiousguy:非类型模板参数。 - Nicol Bolas

17

虚函数能否是常量表达式(constexpr)?

能。自 C++20 开始,虚函数可以是 constexpr


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接