gpt4 book ai didi

c++ - 按值传递的整数常量,视为 constexpr?

转载 作者:IT老高 更新时间:2023-10-28 22:10:15 29 4
gpt4 key购买 nike

虽然我以前用过这样的代码,而且很明显编译器有足够的信息可以工作,但我真的不明白为什么会这样编译:

template <class T, class I>
auto foo(const T& t, I i) {
return std::get<i>(t);
}

int main()
{
std::cerr << foo(std::make_tuple(3,4), std::integral_constant<std::size_t, 0>{});
return 0;
}

实时示例:http://coliru.stacked-crooked.com/a/fc9cc6b954912bc5 .

似乎适用于 gcc 和 clang。问题是,虽然 integral_constant有一个 constexpr转换为存储的整数,constexpr成员函数隐含地将对象本身作为参数,因此这样的函数不能用于 constexpr除非我们调用成员函数的对象本身可以被视为 constexpr .

这里,i是传递给 foo 的参数,因此 i最肯定不能被视为constexpr .然而,确实如此。一个更简单的例子:

template <class I>
void foo(I i) {
constexpr std::size_t j = i;
}

这也可以编译,只要 std::integral_constant<std::size_t, 0>{}传递给 foo .

我觉得我遗漏了一些关于 constexpr 的明显内容规则。无状态类型是否有异常(exception),或者其他什么? (或者,可能是两个主要编译器中的编译器错误?这段代码似乎适用于 clang 5 和 gcc 7.2)。

编辑:已发布答案,但我认为这还不够。特别是,给定 foo 的最后一个定义,为什么会这样:

foo(std::integral_constant<std::size_t, 0>{});

编译,但不是:

foo(0);

0 和 std::integral_constant<std::size_t, 0>{}是常量表达式。

编辑 2:似乎归结为调用 constexpr成员函数即使在一个不是常量表达式的对象上,本身也可以看成是一个常量表达式,只要this未使用。这被认为是显而易见的。我不认为这很明显:

constexpr int foo(int x, int y) { return x; }

constexpr void bar(int y) { constexpr auto x = foo(0, y); }

这不会编译,因为 y传递到 foo不是常量表达式。没用没关系。因此,完整的答案需要显示标准中的某种语言,以证明 constexpr 是正确的。成员函数可以用作常量表达式,即使在非常量表达式对象上,只要 this未使用。

最佳答案

constexpr 改变了编译时常量表达式的规则,很多,但它们并不是新的。在 constexpr 之前,已经有编译时常量表达式了……旧规则在新规范中作为特例保留下来,以避免破坏大量现有代码。

在大多数情况下,旧规则处理的是整数类型的编译时常量,也就是 整数常量表达式...这正是您正在处理的情况。所以不,在 constexpr 规则中没有任何奇怪的东西......这是与 constexpr 无关的其他旧规则。

A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:

...

  • an lvalue-to-rvalue conversion unless it is applied to
    • a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const object with a preceding initialization, initialized with a constant expression, or
    • a non-volatile glvalue that refers to a subobject of a string literal, or
    • a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers to a non-mutable subobject of such an object, or
    • a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;

您说得对,第三个子项目符号不适用。但是第一个可以。

因此,在允许函数返回为编译时常量的新规则(取决于抽象机器上的评估规则)和允许整数值即使不是编译时常量的旧行为之间存在有趣的相互作用标记为这样。


这里有一个简单的例子,为什么 this 是一个隐式参数并不重要。作为一个参数并不意味着一个对象被评估:

constexpr int blorg(bool const flag, int const& input)
{
return flag? 42: input;
}

int i = 5; // 5 is an integral constant expression, but `i` is not
constexpr int x = blorg(true, i); // ok, `i` was an argument but never evaluated
constexpr int y = blorg(false, i); // no way

对于std::integral_constant成员函数,可以考虑blorg函数中的*thisi一样-- 如果执行没有取消引用它,它可以被传递而不是编译时常量。

关于c++ - 按值传递的整数常量,视为 constexpr?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46288958/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com