constexpr函数定义为(c ++ 14)
constexpr函数必须满足以下要求:
- 一定不能虚拟
- 其返回类型必须为LiteralType,其每个参数必须为LiteralType
- 存在至少一组参数值,使得函数的调用可以是a的评估子表达式 核心常量表达式(对于构造函数,在常量中使用) 初始化程序就足够了)(因为C ++ 14)。无需诊断 违反此项目。
函数体必须删除或默认或包含any 陈述除了:
- asm声明
- 一个转到声明
- 带有除case和default之外的标签的声明
- 试用块
- 非文字类型变量的定义
- 静态或线程存储持续时间变量的定义
- 未执行初始化的变量的定义。
现在跟随func1符合要求并编译
constexpr int * func1 (int a)
{
int b = 4;
return &b;
}
int main()
{
constexpr int * a = func1(3);
int arr[*a];
std::cout << a << std::endl;
}
现在我的问题是func1是如何成为constexpr的。它在编译时如何知道局部变量的地址?
我正在使用gcc 6.4.0
答案 0 :(得分:4)
现在我的问题是如何将func1变成constexpr。
你确定吗?
尝试询问编译时值,将其保存在constexpr
变量中;通过例子
constexpr int * a = func1(3);
你应该得到一个错误/警告列表,如(来自我的clang ++ 3.8.1)
tmp_003-14,gcc,clang.cpp:7:11: warning: address of stack memory associated with
local variable 'b' returned [-Wreturn-stack-address]
return &b;
^
tmp_003-14,gcc,clang.cpp:11:21: error: constexpr variable 'a' must be
initialized by a constant expression
constexpr int * a = func1(3);
^ ~~~~~~~~
tmp_003-14,gcc,clang.cpp:11:21: note: pointer to 'b' is not a constant
expression
tmp_003-14,gcc,clang.cpp:6:7: note: declared here
int b = 4;
^
嗯,实际上,从我的g ++ 6.3.0开始,我只得到一个警告
tmp_003-14,gcc,clang.cpp: In function ‘constexpr int* func1(int)’:
tmp_003-14,gcc,clang.cpp:7:7: warning: address of local variable ‘b’ returned [-Wreturn-local-addr]
int b = 4;
^
答案 1 :(得分:4)
如何在编译时知道局部变量的地址?
它没有。
你的引言中的第三个子弹永远不会满足:
至少存在一组参数值,例如a 函数的调用可以是a的一个被评估的子表达式 核心常量表达式(对于构造函数,在常量中使用) 初始化程序就足够了)(因为C ++ 14)。 无需诊断 违反此项目的行为。
编译器不会抱怨它,因为它不是必需的,直到你通过尝试在需要正确的func1
函数的东西中使用constexpr
来进行抱怨,例如:
std::array<int, func(3)> d;
这不会编译,你的编译器会告诉你原因。
答案 2 :(得分:1)
在您的代码中,当func1()
返回时,b
超出了范围。
因此,与b
之外的func1()
相关的任何用法都是未定义的行为。
constexpr int * func1 (int a)
{
int b = 4; // remember: b is non-static
return &b;
}
int * a = func1(3); // b is out of scope here
此外,来自expr.const:
核心常量表达式满足:
(5.2)如果值是指针类型,则它包含一个地址 具有
static
存储持续时间的对象,地址超过结束时间 这样的对象,函数的地址或空指针值
在您的情况下,b
不是static
,这意味着func1()
不 常量表达式。