C++标准是否明确禁止通过 constexpr 成员函数指针调用默认参数?

Does the C++ standard explicitly disallow default arguments in calls through constexpr member function pointers?

本文关键字:指针 函数 成员 调用 默认 参数 constexpr 是否 标准 禁止 C++      更新时间:2023-10-16

请考虑以下代码:

struct foo {
    int bar(int, int = 0) {
        return 0;
    }
};
constexpr auto ptr = &foo::bar;
int main() { 
    return (foo{}.*ptr)(0);
}

正如预期的那样,此代码无法使用最新版本的 GCC、Clang 和 MSVC 进行编译。

但是,假设的编译器能够通过constexpr成员函数指针传递默认参数是合理的。如果这个编译器成功地编译了上面的代码而没有警告,有效地将0, 0传递给foo::bar,它是否仍然符合ISO C++标准?

可接受的答案将参考标准(或其工作草案)。我还没有在工作草案N4567中找到答案。

编辑:如果标准对这个问题没有评论,我也会接受它作为答案。

C++ 标准并没有明确禁止大多数格式错误的构造,包括这个。不明确或隐含地允许它格式不正确就足够了。

允许符合C++的实现接受任何内容,包括格式不正确的C++程序。但是,如果输入不是格式正确的C++程序,则需要发出至少一个诊断(除非标准中存在明确的"无需诊断"子句)。因此,允许符合要求的编译器执行哪些操作的问题取决于所讨论的程序是否格式正确的问题。

为了解决后一个问题,我们应该确定constexpr是否具有任何相关性。答案是肯定的"不"。constexpr 关键字会导致某些原本不是常量表达式的表达式变成常量表达式,并且没有其他含义。反过来,常量表达式与严格限制数量的明确定义的上下文(如数组声明或模板实例化)中的普通香草表达式不同。在这种情况下,非常量表达式会使程序格式不正确。由于所讨论的程序中不存在这样的上下文,因此我们必须得出结论,constexpr与程序的良好形式无关。

特别是,作为常量表达式并不能使表达式免于其类型正确的义务。举个微不足道的例子,

`(int*)nullptr - (int*)nullptr`

格式良好,而

`(int*)nullptr - (double*)nullptr`
类型不正确,

因此格式不正确,尽管两个操作数都是常量表达式,在编译时已知等于 nullptr

免责声明:C 样式转换仅用于演示目的,因为它们在短代码片段中读起来更好。不要在生产代码中使用它们。

因此,我们必须检查程序是否constexpr格式正确。令人惊讶的是,这个问题在标准中没有直接答案,实际上可能根本没有答案。根据C++的静态类型性质,调用应该是格式错误的,但我找不到这种效果的直接语句。与其考虑这样做的潜在影响,我宁愿宣布这是标准的技术缺陷,并称之为一天。

该标准确实间接声明默认函数参数是函数声明的属性,而不是函数本身:

(8.3.6/4)不同作用域的声明具有完全不同的默认参数集

因此,函数

指针作为引用函数而不是函数声明的实体,不应应用默认参数。