5

不出所料,我可以毫无问题地编译下面的示例

// 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; }

我已经知道如何解决这个“问题”,所以我不是在寻求解决方案。我要求一个合理的解释,为什么允许我从非 constexpr 对象调用 constexpr 方法,而不允许我在另一个方法中调用相同的 constexpr 方法(从非 constexpr 'this')。

4

2 回答 2

3

在 C++ 标准中,[dcl.constexpr]/9:

对象声明中使用的 constexpr 说明符将对象声明为 const。这样的对象应具有文字类型并应被初始化。[...] 否则,或者如果在引用声明中使用了 constexpr 说明符,则出现在其初始化程序中的每个完整表达式都应为常量表达式。

现在,编译器隐式添加 athis->到成员函数调用,由 [expr.call]/1 指定

在隐式类成员访问的情况下,隐含对象是 this 指向的对象。[注:形式的成员函数调用f()被解释为(*this).f()(见 9.3.1)。——尾注]

正如jogojapan所指出的(参见聊天讨论),在官方 C++11 标准中,this根据 [expr.const]/2,可能会在类成员访问中作为后缀表达式出现,这里就是这种情况。但是第1369 期的决议不允许使用thisin 常量表达式;但是,函数调用替换可以通过将函数替换为纯右值指针来允许this在函数的上下文中使用。constexpr

C++14 草案删除了关于函数调用替换的小段,以支持 [expr.const]/2 的异常,明确允许在函数this的上下文中使用constexpr(在这种情况下,实际上与什么函数相同)允许调用替换)。


好吧,这不是很“合理”,因为它没有提供以这种方式指定的原因,它只提供了编译器拒绝它的原因。

于 2013-07-05T03:17:33.447 回答
0

可以constexpr在任何上下文中调用函数,无论是否为常量表达式。(你sample_method_second甚至不是constexpr。)但是constexpr必须在编译时评估一个对象。

那么什么sample_method_second是要求编译器在编译时使用this来获取结果sample_method_first。显然这是不可能的。

不同之处在于,在第一个示例中, 的范围main允许编译器调用 上的方法sample_object。但是能够评估一个对象的值并不能扩展到程序中的所有潜在对象,这就是sample_method_second事实。

解决方案(好吧,除了sample_method_first独立于thisusing static)不是声明sample_variableconstexpr. 如果您以需要的方式使用它constexpr,那么您的设计就有缺陷,因为一个成员函数实际上需要在最终程序中实现多个(可能是无限的)实现。

请记住,合法变量的每个潜在不同值都constexpr可能产生新的模板实例化、不同组织switchstatic_assert. 尝试在运行时追溯执行!


至于为什么允许第一种情况:

sample_struct sample_object;
constexpr int sample_variable = sample_object.sample_method();

这里发生的是constexpr函数调用,其规则不包括

— 对文字类的 constexpr 构造函数以外的函数的调用、constexpr 函数或对普通析构函数的隐式调用 (12.4)

根本不要求对象是constexpr,因为如果某些东西需要保持不变来评估函数的内部,或者使用函数的结果,那么根据其他规则之一(例如 lvalue-),评估会出错右值转换。您将无法修改sample_method以实际访问任何内容,这样做会抱怨sample_object未声明constexpr,或者如果您尝试直接使用的值,它的地址不是常量this

于 2013-07-05T03:49:02.727 回答