简体   繁体   English

在C ++中使用同一类的另一个方法中的constexpr方法

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM