正如预期的那样,我可以编译下面的示例而没有任何问题
// first_sample.cpp
struct sample_struct
{
constexpr int
sample_method()
{ return 5; }
};
int main()
{
sample_struct sample_object;
constexpr int sample_variable = sample_object.sample_method();
return 0;
}
但我无法编译以下示例
'this'不是常量表达式
// second_sample.cpp
struct sample_struct
{
constexpr int
sample_method_first()
{ return 5; }
void
sample_method_second()
{ constexpr int sample_variable = sample_method_first();
/* Do something with sample_variable */ }
};
int main()
{ return 0; }
我已经知道如何解决这个“问题”,所以我不是要求解决方案。 我要求一个合理的解释为什么我被允许从a调用constexpr方法 非constexpr对象虽然我不被允许在另一个方法中调用相同的constexpr方法(来自非constexpr'this')。
答案 0 :(得分:3)
在C ++标准中,[dcl.constexpr] / 9:
对象声明中使用的constexpr说明符将对象声明为const。这样的对象应具有文字类型并应初始化。 [...]否则,或者如果在引用声明中使用constexpr说明符,则其初始值设定项中出现的每个完整表达式都应为常量表达式。
现在,编译器隐式地向成员函数调用添加this->
,由[expr.call] / 1
在隐式类成员访问的情况下,隐含的对象是由此指向的对象。 [注意:
f()
形式的成员函数调用被解释为(*this).f()
(见9.3.1)。 - 后注]
正如jogojapan指出的那样(参见chat discussion),在官方C ++ 11标准中,this
可能在类成员访问中作为postfix-expression出现,如[expr]所示.const] / 2,这就是这种情况。但是Issue 1369的解决方案不允许在常量表达式中使用this
;但是,函数调用替换可以允许在this
函数的上下文中使用constexpr
,方法是用prvalue指针替换它。
C ++ 14草案删除了关于函数调用替换的子段,支持[expr.const] / 2的一个例外,明确允许在{expour.const] / 2中使用this
constexpr
函数的上下文(在这种情况下实际上与允许的函数调用替换相同)。
嗯,这不是很“合理”,因为它没有提供为什么以这种方式指定的原因,它只提供了编译器拒绝它的原因。
答案 1 :(得分:0)
可以在任何上下文中调用constexpr
函数,是否为常量表达式。 (而你的sample_method_second
甚至不是constexpr
。)但是必须在编译时评估constexpr
对象。
那么sample_method_second
的作用是要求编译器在编译时使用this
来获取sample_method_first
的结果。显然这是不可能的。
不同之处在于,在第一个示例中,main
的范围允许编译器调用sample_object
上的方法。但是能够评估一个对象的值并不会扩展到程序中的所有潜在对象,这是sample_method_second
所做的。
解决方案(除了sample_method_first
使用this
独立于static
)之外,不要将sample_variable
声明为constexpr
。如果你以一种需要constexpr
的方式使用它,那么你的设计是有缺陷的,因为一个成员函数在最终程序中实际上需要多个(可能是无限的)实现。
请记住,合法constexpr
变量的每个潜在不同值可能会生成新的模板实例化,组织不同的switch
或停止使用static_assert
的编译。尝试在运行时追溯执行!
至于为什么允许第一种情况:
sample_struct sample_object;
constexpr int sample_variable = sample_object.sample_method();
这里发生的是constexpr
函数调用,其规则排除
- 为文字类,constexpr函数或简单析构函数的隐式调用调用constexpr构造函数以外的函数(12.4)
根本没有要求对象为constexpr
,因为如果某些东西需要不变来评估函数的内部,或者使用函数的结果,那么评估就会出现错误。其他规则,如左值到右值的转换。您将无法修改sample_method
以实际访问任何内容,并且这样做会抱怨sample_object
未声明为constexpr
,或者如果您尝试使用其地址不是常量直接this
的值。