Ayx*_*xan 14 c++ pointers language-lawyer constexpr c++17
这是有效的 C++ 吗?
int main() {
constexpr auto sz = __func__ - __func__;
return sz;
}
Run Code Online (Sandbox Code Playgroud)
GCC 和 MSVC 认为可以,Clang 认为不是:Compiler Explorer。
所有编译器都同意这个是可以的:Compiler Explorer。
int main() {
constexpr auto p = __func__;
constexpr auto p2 = p;
constexpr auto sz = p2 - p;
return sz;
}
Run Code Online (Sandbox Code Playgroud)
Clang 再次不喜欢这个,但其他人都可以:编译器资源管理器
int main() {
constexpr auto p = __func__;
constexpr auto p2 = __func__;
constexpr auto sz = p2 - p;
return sz;
}
Run Code Online (Sandbox Code Playgroud)
这里有什么?我认为对无关指针的算术是未定义的行为,但__func__返回相同的指针,不是吗?我不确定,所以我想我可以测试一下。如果我没记错的话,std::equal_to可以比较不相关的指针而没有未定义的行为:
#include <functional>
int main() {
constexpr std::equal_to<const char*> eq{};
static_assert(eq(__func__, __func__));
}
Run Code Online (Sandbox Code Playgroud)
Clang 认为eq(__func__, __func__)不是一个常量表达式,即使std::equal_to::operator() 是 constexpr。其他编译器不会抱怨: Compiler Explorer
Clang 也不会编译这个。抱怨__func__ == __func__不是一个常量表达式:编译器资源管理器
int main() {
static_assert(__func__ == __func__);
}
Run Code Online (Sandbox Code Playgroud)
Nic*_*las 13
__func__在 C++ 中是一个标识符。特别是,它引用了一个特定的对象。来自[dcl.fct.def.general]/8:
函数局部预定义变量
__func__被定义为好像是表单的定义Run Code Online (Sandbox Code Playgroud)static const char __func__[] = "function-name";已提供,其中 function-name 是实现定义的字符串。不确定这样的变量是否具有不同于程序中任何其他对象的地址。
作为函数局部预定义变量,这个定义(好像)出现在函数块的开头。因此,__func__该块内的任何使用都将引用该变量。
至于“任何其他对象”部分,变量定义了一个对象。__func__命名由该变量定义的对象。因此,在一个函数内,所有使用__func__name 的变量都相同。未定义的是该变量是否是与其他对象不同的对象。
也就是说,如果您在名为 的函数中foo,并且您"foo"在问题的其他地方使用了文字,则不禁止实现使变量__func__也与文字"foo"返回的对象相同。也就是说,标准并不要求__func__出现的每个函数都必须存储与字符串文字本身分开的数据。
现在,C++ 的“好像”规则允许实现偏离这一点,但它们不能以可检测的方式进行。因此,虽然变量本身可能有也可能没有与其他对象不同的地址,但__func__在同一个函数中使用的必须表现得好像它们引用同一个对象。
Clang 似乎没有以__func__这种方式实现。它似乎实现了它,就好像它返回了函数名称的纯右值字符串文字。两个不同的字符串文字不必引用同一个对象,因此减去指向它们的指针就是 UB。常量表达式上下文中的未定义行为是格式错误的。
唯一让我犹豫地说 Clang 在这里是 100% 错误的是[temp.arg.nontype]/2:
对于引用或指针类型的非类型模板参数,常量表达式的值不得引用(或对于指针类型,不得为以下地址):
...
- 预定义的
__func__变量。
看,这似乎允许通过实现进行一些捏造。也就是说,虽然__func__技术上可以是一个常量表达式,但不能在模板参数中使用它。它被视为字符串文字,即使它在技术上是一个变量。
所以在某种程度上,我会说这个标准是从双方嘴里说出来的。