函数指针的两个constexpr实例的差异仍然是constexpr吗? 这是有效的C++?< /p> int main() { constexpr auto sz = __func__ - __func__; return sz; }

函数指针的两个constexpr实例的差异仍然是constexpr吗? 这是有效的C++?< /p> int main() { constexpr auto sz = __func__ - __func__; return sz; },c++,pointers,language-lawyer,c++17,constexpr,C++,Pointers,Language Lawyer,C++17,Constexpr,GCC和MSVC认为没问题,Clang认为没问题 所有编译器都同意这一个是可以的: 叮当声又一次不喜欢这个,但其他人都同意: 上面是什么?我认为不相关指针上的算术是未定义的行为,但是\uuuu func\uuu返回相同的指针,不是吗?我不确定,所以我想我可以测试一下。如果我没有记错的话,std::equal_to可以比较不相关的指针,而没有未定义的行为: #include <functional> int main() { constexpr std::equal_t

GCC和MSVC认为没问题,Clang认为没问题


所有编译器都同意这一个是可以的:


叮当声又一次不喜欢这个,但其他人都同意:


上面是什么?我认为不相关指针上的算术是未定义的行为,但是
\uuuu func\uuu
返回相同的指针,不是吗?我不确定,所以我想我可以测试一下。如果我没有记错的话,
std::equal_to
可以比较不相关的指针,而没有未定义的行为:

#include <functional>

int main() {
    constexpr std::equal_to<const char*> eq{};
    static_assert(eq(__func__, __func__));
}

C++中的代码>代码>函数>代码>是一个标识符。特别是,它引用一个特定的对象。发件人:

函数局部预定义变量
\u­­­­­­­­
的定义与表单的定义相同

static const char __func__[] = "function-name";
已提供,其中函数名是实现定义的字符串。未指定此类变量是否具有与程序中任何其他对象不同的地址

作为示例,此定义(好像)出现在功能块的开头。因此,在该块中使用
\uuuu func\uuu
将引用该变量

至于“任何其他对象”部分,变量定义了一个对象
\uuu func\uu
命名该变量定义的对象。因此,在一个函数中,
\uuuuu func\uuu
的所有用法都命名为同一个变量。未定义的是该变量是否是与其他对象不同的对象

也就是说,如果您在一个名为
foo
的函数中,并且在问题的其他地方使用了literal
“foo”
,则不禁止实现将变量
\uuu func\uu
与literal
“foo”
返回的对象相同。也就是说,该标准并不要求出现
\uuuu func\uuu
的每个函数必须存储与字符串文本本身分离的数据

现在,C++的“似乎”规则允许实现偏离这一点,但它们不能以可检测的方式实现。因此,虽然变量本身可能有或可能没有与其他对象不同的地址,但在同一函数中使用
\uuu func\uu
时必须表现为它们引用同一对象

Clang似乎没有以这种方式实现
\uuuuu func\uuuu
。它似乎实现了它,就好像它返回了函数名的prvalue字符串文本一样。两个不同的字符串文本不必引用同一个对象,因此减去指向它们的指针是非常困难的。在常量表达式上下文中,未定义的行为是病态的

唯一让我犹豫不决的是,在这里说叮当是100%错误的是:

对于引用或指针类型的非类型模板参数,常量表达式的值不应引用(或对于指针类型,不应是的地址):

  • 预定义的
    \ufunc\ufunc
    变量
看,这似乎允许实施过程中的一些捏造。也就是说,虽然从技术上讲,
\uuu func\uu
可以是一个常量表达式,但不能在模板参数中使用它。它被视为字符串文字,尽管从技术上讲它是一个变量


因此,在某种程度上,我可以说,该标准是在口是心非。

从中,
\uuu func\uuu
就好像
静态常量char\uu func\uu[]=“函数名”
和这个等价物被接受…有趣的是,如果你用
\uuuuu func\uuuu
初始化一个constepr变量,并在static\u assert中使用它…@Jarod42那么这是Clang中的一个bug?@florestan like?它也不会用叮当声编译。我在问题中的第二个和第三个例子就是你提到的方式。一个编译,另一个不编译。另请参阅,这可能会从constexpr求值中完全删除
\uuuuu func\uuuu
。因此,严格地说,
\uuuu func\uuu
在我的问题中的所有情况下都可以是常量表达式,对吗?那么代码应该已经编译好了。关于“这个变量是否有一个不同于程序中任何其他对象的地址是未指定的”部分呢?未指定行为是指抽象机器行为中的非确定性。这对constexpr评估有问题吗?如果第一次出现的
\uuuuu func\uuu
的地址与另一个对象的地址相同,而第二次出现的
\uuuu func\uuu
的地址不相同,该怎么办?当然,这并不意味着这两个实例的地址不同,但我仍然感到困惑@Johanneschaub litb:“关于”这个变量是否有一个不同于程序中任何其他对象的地址还没有确定。“部分”呢<代码>\uuuu func\uuu不是宏;它是一个标识符,用于命名特定变量,从而命名特定对象。因此,在同一函数中使用
\uuuu func\uuu
时,应产生引用同一对象的glvalue。或者更重要的是,它不能以这样的方式实现,即不会出现这种情况。@Nicol引用同一对象。但该对象可能在某一时刻与另一个对象具有相同的地址。而在另一个瞬间,我却没有。我不是说这是一个问题,但我只是提醒大家这种可能性。然后,我也可能弄错了,所以我也希望能被纠正或确认。@但是,这个对象可能在同一个时刻有和另一个对象相同的地址。“在C++对象模型下是不允许的。两个对象,一个不嵌套在另一个中,不能同时在同一存储中都在其生命周期内。而且所讨论的对象具有静态存储持续时间,因此除非在其上使用placement-
new
,否则在程序结束之前,它不会移动到任何地方。
#include <functional>

int main() {
    constexpr std::equal_to<const char*> eq{};
    static_assert(eq(__func__, __func__));
}
int main() {
    static_assert(__func__ == __func__);
}
static const char __func__[] = "function-name";