c++ 从立即函数返回std::vector

iszxjhcz  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(77)

从C20开始,std::vector就可以在常量表达式中使用。据我所知,目前的C允许动态分配内存,条件是任何这样的分配在常量表达式“结束”时被释放。
然而,我遇到的情况下,立即函数的规则可能是不同的。请考虑的例子:

consteval auto getVec() {
    return std::vector<int>(9);
}

static_assert( getVec().size() == 9 );

字符串
这里立即consteval函数getVec返回非空的std::vector,其大小在常量表达式中验证。
我希望这段代码能够编译,因为所有的释放都必须自动完成,而且在Clang中,libc++确实接受了这段代码。
但MSVC抱怨说:

error C7595: 'getVec': call to immediate function is not a constant expression
note: (sub-)object points to memory which was heap allocated during constant evaluation
fatal error C1903: unable to recover from previous error(s); stopping compilation


GCC的行为类似:

error: 'getVec()()' is not a constant expression because it refers to a result of 'operator new'


在线演示:https://gcc.godbolt.org/z/d736qr3hh
这里哪个编译器是正确的?

xwmevbvl

xwmevbvl1#

这是固定的,P2564R3被接受为C++20的缺陷报告。它允许getVec()成为一个更大的常量表达式的子表达式,而不是本身的常量表达式。
LLVM 17和即将到来的GCC 14实现了它。对于MSVC,有一个feature request

问题的最初原因是这样的:
[expr.prim.id]p3:
表示立即函数([dcl.constexpr])的可能求值的 id-expression 应仅出现

  • 作为立即调用的子表达式,或
  • 在立即函数上下文中([expr.const])

[expr.const]p13:
如果一个表达式或转换是潜在求值的,并且它的最里面的非块作用域是一个立即函数的函数参数作用域,那么它就在一个 * 立即函数上下文中。如果一个表达式或转换是一个立即函数的潜在求值的显式或隐式调用,并且不在一个立即函数上下文中,那么它就是一个 * 立即调用 *。一个立即调用应该是一个常量表达式。
static_assert( getVec().size() == 9 );不在立即函数上下文中。因此,显式调用getVec()是立即调用,因此它需要生成常量表达式。getVec()本身不是常量表达式,因为它不会释放new分配的内存。
为了进行比较,下面的代码确实编译了https://godbolt.org/z/9KqhY7oP8

consteval auto getVec() {
    return std::vector<int>(9);
}

consteval auto getVecSize() {
    return getVec().size();
}

static_assert(getVecSize() == 9);
static_assert([]() consteval { return getVec().size() == 9; }());

consteval void InAnImmediateFunctionContext() {
    static_assert(getVec().size() == 9);
}

字符串

相关问题