【问题标题】:constexpr returning array, gcc warningconstexpr 返回数组,gcc 警告
【发布时间】:2014-08-31 19:56:49
【问题描述】:

我写了一个返回数组的 constexpr 函数。

#include <iostream>

constexpr auto get_str(void)
-> const char(&)[4] {   
    return { 'T', 'E', 'S', 'T' };
}

constexpr int sum(const char(&str)[4]){
    return str[0] + str[1] + str[2] + str[3];
}

int main(void){

    constexpr int s = sum(get_str());

    std::cout << s << std::endl;

    return 0;
}

g++ 4.8 可以正确编译代码,但会发出以下警告:

test.cpp: In function ‘constexpr const char (& get_str())[4]’:
test.cpp:5:30: warning: returning reference to temporary [-Wreturn-local-addr]
  return { 'T', 'E', 'S', 'T' };

在这种情况下警告是否正确?从这样的 constexpr 函数返回数组是否不正确,即使该函数从未在运行时实际调用,仅在编译期间调用?

【问题讨论】:

  • 你可以使用std::array&lt;char,4&gt;按值返回一个constexpr静态数组,而不是返回一个引用。
  • @MikaelPersson 谢谢,我曾一度尝试使用 std::array,但我的完整代码正在做一些奇怪的事情,需要在编译时转换为 const char*,但我做不到&arr[0] 在常量表达式中。

标签: c++ arrays gcc constexpr gcc-warning


【解决方案1】:

clang 3.4 不会编译此代码,因为 sum(get_str()) 不是 constexpr,据我所知,clang 在这里是正确的,这一行 (see it live):

constexpr int s = sum(get_str());

产生以下错误:

error: constexpr variable 's' must be initialized by a constant expression
constexpr int s = sum(get_str());
              ^   ~~~~~~~~~~~~~~

note: read of temporary whose lifetime has ended
return str[0] + str[1] + str[2] + str[3] 
       ^

这不是一个有效的constexpr 有两个原因。这会调用未定义的行为,这是explicitly disallowed in a constant expression,总结the draft C++ standard 部分5.19 说:

条件表达式 e 是核心常量表达式,除非 e 的求值,

并包含以下项目符号:

具有未定义行为的操作

在其生命周期之外的访问将是。我们知道在这种情况下临时对象的生命周期不会从12.2 临时对象部分延长,它说:

第二个上下文是当一个引用绑定到一个临时的。117 引用绑定到的临时对象或作为临时对象的临时对象 引用绑定到的子对象的完整对象 在引用的生命周期内持续存在,除了

并包括以下项目符号:

临时绑定到函数中返回值的生命周期 return 语句 (6.6.3) 未扩展;临时被毁 在 return 语句中的完整表达式的末尾。

因此,虽然 常量表达式 确实不能保证在翻译时被评估,但我们在 5.19 常量表达式 部分中有一个注释提到了这一点(强调我的未来):

注意:常量表达式可以在翻译过程中求值。—end 注意]

即使保证我们仍然不会被允许调用未定义的行为。

第二个问题是 constexpr 引用必须是静态存储持续时间的对象或函数,cppreference 在其core constant expression section 中提到了这一点:

引用常量表达式是一个左值核心常量表达式 指定具有静态存储持续时间的对象或函数

据我所知,这在5.19常量表达式4段中有所介绍,其中说:

每个引用类型的非静态数据成员引用一个对象 静态存储持续时间或函数,

【讨论】:

    【解决方案2】:

    函数从不在运行时实际调用,仅在运行时调用 编译?

    标准不保证完全。编译器完全有权在运行时调用它。

    constexpr temporaries 永远不会死如果编译器在编译时调用它。编译器没有义务。

    【讨论】:

    • 它没有义务,但它肯定是在编译时查看程序集。我想这个警告是有道理的,如果不能保证,我会避免这样做。
    • 我知道这是旧的,但我在另一个问题中看到了这一点,它在这里是相关的:“除了能够在编译时评估表达式,我们希望能够 require要在编译时评估的表达式;变量定义前面的 constexpr 会这样做(并暗示 const):"
    猜你喜欢
    • 2010-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-05
    相关资源
    最近更新 更多