Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 将本地字符串参数作为对const的引用传递到constexpr函数中?为什么这是合法的?_C++_C++11_Constexpr - Fatal编程技术网

C++ 将本地字符串参数作为对const的引用传递到constexpr函数中?为什么这是合法的?

C++ 将本地字符串参数作为对const的引用传递到constexpr函数中?为什么这是合法的?,c++,c++11,constexpr,C++,C++11,Constexpr,constexpr函数只接受文本类型的参数。类字符串的对象本身不是文本类型,而是指针(标量类型)或引用是文本类型。因此,对字符串的引用是一种文字类型 此外,如果constexpr函数的参数也是常量表达式,则它只返回常量表达式 “如果scale*函数的参数为 是一个常量表达式,但除此之外:“ 来源:C++入门,第五版< /P> 在本例中,比例较短() 现在,我在这里将字符串的两个引用传递给一个constexpr函数,该函数不保留在固定地址(全局或静态),而是保留在变量地址(本地)。因此,这两个参数

constexpr函数只接受文本类型的参数。类字符串的对象本身不是文本类型,而是指针(标量类型)或引用是文本类型。因此,对字符串的引用是一种文字类型

此外,如果constexpr函数的参数也是常量表达式,则它只返回常量表达式

“如果scale*函数的参数为 是一个常量表达式,但除此之外:“
来源:C++入门,第五版< /P> 在本例中,比例较短()

现在,我在这里将字符串的两个引用传递给一个constexpr函数,该函数不保留在固定地址(全局或静态),而是保留在变量地址(本地)。因此,这两个参数不应该是常量表达式。
constexpr函数的结果被分配给constexpr bool

运行:

$ ./ex646
address of shrt 0x7ffd39e41a50 # every time different
address of longer 0x7ffd39e41a40 # every time different, always 0x10 more than &shrt
shrt is shorter
string 0
string& 1
string* 1
编译器如何比较两个字符串的地址?它们在程序的每个运行时都是不同的,而它们的相对位置保持不变。这种用法的关键是,至少它们彼此的相对位置保持不变吗

更新2015-08-12
在撰写本文时,这看起来像是ISO标准中的“常量评估规则中的错误”(如果我错了,请纠正我)。请参见isocpp.org列表。因此,这不应该是GCC和CLANG中的编译器错误


谢谢,戴普

字符串的地址是堆栈对象的地址,而不是字符串正在包装的底层指针。每次运行时地址可能不同,但编译器每次都会以相同的方式将变量加载到内存中,因此比较将始终产生相同的结果

注意:不同的编译器可能以不同的方式对变量排序,因此此代码不可移植

注2:为相等(=,!=)比较指针是为相同类型的指针定义的行为。如果出现以下情况,则未指定尝试与关系运算符(,=)进行比较:

同一类型的两个指针p和q指向不同的对象,这些对象不是同一对象的成员或同一数组的元素,也不是指向不同的函数,或者如果其中只有一个为null


据我所知,这看起来像某种编译器扩展或bug。C++11通过缺陷报告进行了调整,以允许将引用视为文字类型,而不管它引用的变量是否为文字类型。但是,引用常量表达式应该引用具有静态存储持续时间的对象,类似于地址常量表达式

C++11标准草案告诉我们指针可以被视为相等的情况:

如果相同类型的两个指针比较相等,则 只有当它们都为null时,它们都指向同一个函数,或者都表示相同的地址(3.9.2)

因此,在您的情况下,编译器可以简单地推断出
是哪种情况=
属于这种情况,但我没有看到一个可以避免这种情况下的常量表达式要求的切口

参考章节
5.19
[expr.const]告诉我们:

引用引用类型的变量或数据成员的id表达式,除非该引用具有 在初始化之前,使用常量表达式初始化

对其进行了修改,修改如下:

引用引用类型的变量或数据成员的id表达式,除非该引用具有 在初始化之前,以及

  • 它是用常量表达式或
  • 它是一个对象的非静态数据成员,其生存期开始于对e的求值
但在任何一种情况下,这都足以使该情况不是一个常数表达式

引用常量表达式是左值 指定具有静态存储持续时间的对象或函数的核心常量表达式。地址 常量表达式是指针类型的prvalue核心常量表达式,其计算结果为 具有静态存储持续时间的对象、函数地址、空指针值或prvalue核心 std::nullptr\t类型的常量表达式

这些都不适用于您案例中的自动变量

引用最初不是文字,但表示:

7.1.5[dcl.constexpr]第3段要求constexpr函数或构造函数的引用参数和返回类型必须引用文本类型,这一点限制性太强。5.20[expr.const]第2段已经防止了非文字类型的左值的任何有问题的使用,并且它允许使用指向非文字类型的指针作为地址常量。通过引用参数和constexpr函数的返回类型也应该允许这样做

并更改了
3.9
[basic.types]一节,该节在
N3337
C++11标准草案中指出:

如果类型是:

[……]

  • 引用文本类型的引用类型;或
致:

  • 参考类型;或

谢谢在接受你的答案之前,最后再问一个问题。这不是实现定义的行为?如果我没记错的话,比较地址看哪个更大实际上是未定义的行为!更实际的情况是,一些编译器会在堆栈上分配局部变量,从最大地址开始,然后变小,而不是从最小地址开始,然后变大。当然,它可以做任何它想做的事(除了给他们相同的地址)谢谢。因此,将指针仅用于相等似乎是一种行为定义。此外,我在一个答案中看到了这个链接,它在几分钟前被删除了(为什么?):如果用亲戚测试它
$ g++ -o ex646 ex646.cpp -std=gnu++11 -Wall -Wpedantic
$ ./ex646
address of shrt 0x7ffd39e41a50 # every time different
address of longer 0x7ffd39e41a40 # every time different, always 0x10 more than &shrt
shrt is shorter
string 0
string& 1
string* 1