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

时间:2013-07-05 02:54:50

标签: c++

正如预期的那样,我可以编译下面的示例而没有任何问题

// 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')。

2 个答案:

答案 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的值。