[英]Using a constexpr method inside another method of the same class in C++
As expected, I can compile the sample below without any problems 正如所料,我可以毫无问题地编译下面的示例
// 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;
}
But i cannot compile the following sample for the reason 但我无法编译以下示例
'this' is not a constant expression
'这'不是一个恒定的表达
// 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; }
I already know how to solve this "problem" so i am not asking for a solution. 我已经知道如何解决这个“问题”所以我不是要求解决方案。 I am asking for a reasonable explanation why i am allowed to call a constexpr method from a non-constexpr object while i am not allowed to call the same constexpr method inside another method (from non-constexpr 'this').
我要求一个合理的解释为什么我被允许从非constexpr对象调用constexpr方法, 而我不允许在另一个方法中调用相同的constexpr方法(来自非constexpr'this')。
In the C++ Standard, [dcl.constexpr]/9: 在C ++标准中,[dcl.constexpr] / 9:
A constexpr specifier used in an object declaration declares the object as const.
对象声明中使用的constexpr说明符将对象声明为const。 Such an object shall have literal type and shall be initialized.
这样的对象应具有文字类型并应初始化。 [...] Otherwise, or if a constexpr specifier is used in a reference declaration, every full-expression that appears in its initializer shall be a constant expression.
[...]否则,或者如果在引用声明中使用constexpr说明符,则其初始值设定项中出现的每个完整表达式都应为常量表达式。
Now, the compiler implicitly adds a this->
to the member function call, as specified by [expr.call]/1 现在,编译器隐式地将
this->
添加到成员函数调用中,由[expr.call] / 1指定
In the case of an implicit class member access, the implied object is the one pointed to by this.
在隐式类成员访问的情况下,隐含的对象是由此指向的对象。 [Note: a member function call of the form
f()
is interpreted as(*this).f()
(see 9.3.1).[注意:形式为
f()
的成员函数调用被解释为(*this).f()
(见9.3.1)。 —end note ]- 尾注]
As jogojapan has pointed out (see chat discussion ), in the official C++11 Standard, this
may occur as postfix-expression in a class member access as per [expr.const]/2, which is the case here. 正如jogojapan指出的那样(参见聊天讨论 ),在官方的C ++ 11标准中,
this
可能在类成员访问中作为postfix-expression出现,如[expr.const] / 2所示,这就是这里的情况。 But the resolution of Issue 1369 disallowed any use of this
in constant expressions; 但问题1369的决议不允许在不断表达中使用
this
; however function invocation substitution can allow using this
within the context of a constexpr
function by replacing it with a prvalue pointer. 然而功能调用取代可以允许使用
this
一范围内constexpr
通过用prvalue指针代替它的功能。
The C++14 draft removes the sub-paragraph about function invocation substitution in favour of an exception to [expr.const]/2, explicitly allowing the use of this
within the context of a constexpr
function (in this case effectively the same as what function invocation substitution allowed). 在C ++ 14草案去除分段约函数调用置换赞成异常的为[expr.const] / 2,明确地允许使用
this
一范围内constexpr
函数(在这种情况下,实际上是相同的允许什么函数调用替换)。
Well, this isn't very "reasonable" as it doesn't provide the reason why it is specified in this way , it only provides the reason why the compiler rejects it. 嗯,这不是很“合理”,因为它没有提供以这种方式指定的原因,它只提供了编译器拒绝它的原因。
A constexpr
function may be called in any context, constant expression or not. constexpr
函数可以在任何上下文中调用,是否为常量表达式。 (And your sample_method_second
isn't even constexpr
.) But a constexpr
object must be evaluated at compile time. (而且你的
sample_method_second
甚至不是constexpr
。)但是必须在编译时评估constexpr
对象。
So what sample_method_second
does is ask the compiler to use this
to get the result of sample_method_first
at compile time. 那么
sample_method_second
作用是要求编译器在编译时使用this
来获取sample_method_first
的结果。 Clearly that's impossible. 显然这是不可能的。
The difference is that in the first example, the scope of main
allows the compiler to call the method on sample_object
. 不同之处在于,在第一个示例中,
main
的范围允许编译器在sample_object
上调用该方法。 But being able to evaluate the value of one object does not extend to all potential objects in the program, which is what sample_method_second
does. 但是能够评估一个对象的值并不会扩展到程序中的所有潜在对象,这就是
sample_method_second
所做的。
The solution (well, aside from making sample_method_first
independent of this
using static
) is not to declare sample_variable
as constexpr
. 解决方案(除了使用
static
使sample_method_first
独立this
)不是将sample_variable
声明为constexpr
。 If you're using it in a way that requires constexpr
, then your design is flawed because the one member function would actually need multiple (potentially infinite) implementations in the final program. 如果你以一种需要
constexpr
的方式使用它,那么你的设计是有缺陷的,因为一个成员函数实际上需要在最终程序中实现多个(可能是无限的)实现。
Remember, each potential different value of a legitimately constexpr
variable may produce a new template instantiation, a differently-organized switch
, or halt compilation with a static_assert
. 请记住,合法
constexpr
变量的每个潜在的不同值可能会产生新的模板实例化,不同组织的switch
,或者使用static_assert
停止编译。 Try doing that retroactively at runtime! 尝试在运行时追溯执行!
As for why the first case is allowed: 至于为什么允许第一种情况:
sample_struct sample_object;
constexpr int sample_variable = sample_object.sample_method();
What's happening here is constexpr
function invocation, and the rule for that excludes 这里发生的是
constexpr
函数调用,其规则排除在外
— an invocation of a function other than a constexpr constructor for a literal class, a constexpr function, or an implicit invocation of a trivial destructor (12.4)
- 为文字类,constexpr函数或简单析构函数的隐式调用调用除constexpr构造函数之外的函数(12.4)
There simply isn't a requirement that the object be constexpr
because if something needs to be constant to evaluate the inside of the function, or use the result of the function, the evaluation will go awry according to one of the other rules such as lvalue-to-rvalue conversion. 根本没有要求对象是
constexpr
因为如果某些东西需要是常量来评估函数的内部,或者使用函数的结果,那么评估将根据其他规则(如左值)进行评估。到左值转换。 You won't be able to modify sample_method
to actually access anything, and doing so will complain that sample_object
is not declared constexpr
, or that its address is not constant if you try to use the value of this
directly. 您将无法修改
sample_method
实际访问任何东西,这样做会抱怨sample_object
未声明constexpr
,或它的地址是不恒定的,如果你尝试使用的价值this
直接。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.