代码之家  ›  专栏  ›  技术社区  ›  n. m. could be an AI

即时函数的参数

  •  0
  • n. m. could be an AI  · 技术社区  · 5 年前

    在C++17中,这段代码是非法的:

    constexpr int foo(int i) {
        return std::integral_constant<int, i>::value;
    }
    

    那是因为即使 foo 如果可以在编译时进行评估,编译器仍然需要生成在运行时执行它的指令,因此无法进行模板实例化。

    在C++20中,我们将有 consteval 函数,这些函数需要在编译时进行求值,因此应删除运行时约束。这是否意味着该代码将是合法的?

    consteval int foo(int i) {
        return std::integral_constant<int, i>::value;
    }
    
    0 回复  |  直到 6 年前
        1
  •  48
  •   Nicol Bolas    6 年前

    不。

    无论这篇论文会带来什么变化,都很小 at this point ,它不能改变非模板函数定义只键入一次的事实。此外,如果你提出的代码是合法的,我们大概可以找到一种方法来声明一个类型的变量 std::integral_constant<int, i> ,这在网上解决方面感觉非常令人望而却步。

    本文还指出,在一个例子中,参数不应被视为核心常数表达式;

    consteval int sqrsqr(int n) {
      return sqr(sqr(n)); // Not a constant-expression at this  point,
    }                     // but that's okay.
    
    

    简而言之,由于可能存在类型差异,函数参数永远不会是常量表达式。

        2
  •  36
  •   Barry    6 年前

    这是否意味着该代码将是合法的?

    consteval int foo(int i) {
        return std::integral_constant<int, i>::value;
    }
    

    不,这仍然是不明智的。虽然 consteval 要求调用本身是一个常量表达式,因此您知道生成的参数 i 必须是一个常数表达式, foo 它本身仍然不是一个模板。模板?

    示例中的细微变化可能会使这一点更加明显:

    consteval auto foo(int i) {
        return std::integral_constant<int, i>();
    }
    

    如果这是有效的, foo(1) foo(2) 会。。。返回不同的类型。这是一个完全不同的语言特性( constexpr function parameters )-因为为了使其工作,这些函数真的需要表现得像模板一样。

    这可能看起来有点不直观。毕竟,如果产生的论点 毫无疑问,这是一个不变的表达 它也应该作为一个整体使用吗?但它仍然不是——[expr.const]中没有允许立即函数参数的其他异常。立即函数仍然只是一个函数,它的参数仍然不是常量表达式——就像普通函数一样 constexpr 函数的参数不是常量表达式。


    当然有 int ,我们可以重写函数,将函数参数提升为模板参数:

    template <int i>
    consteval int foo() {
        return std::integral_constant<int, i>::value;
    }
    

    C++20为我们提供了类类型作为非类型模板参数,因此我们实际上可以对比以前更多的类型执行此操作。但是仍然有很多类型可以用作即时函数的参数,而不能用作模板参数,因此这并不总是有效的(例如。 std::optional 或者更令人兴奋的是在C++20中, std::string ).

        3
  •  9
  •   Michael Kenzel    6 年前

    这在C++20中似乎是不合法的。@Barry和@Columbo的回答中已经给出了一个很好的解释,说明为什么支持这一点会有问题(它实际上不适用于类型系统)。我只会添加我认为是标准中的相关引用,这些引用实际上使这成为非法。

    基于 [temp.arg.nontype]/2

    A. 模板参数 对于非类型 模板参数 应为转换后的常数表达式[]

    转换后的常量表达式是隐式转换为特定类型的常量表达式 [expr.const]/7 (此处为模板参数的类型)。所以,你的问题归结为一个问题,即一个consteval函数内的变量是否是一个常量表达式。基于 [expr.const]/8

    常量表达式是指作为常量表达式(如下定义)的允许结果的实体的glvalue核心常量表达式,或者是其值满足以下约束的pr值核心常量表达式:[]

    表达 i 是一个glvalue id表达式 这是一个核心常量表达式(因为它的求值不执行中列出的任何操作 [expr.const]/4 ). 但是,此核心常量表达式引用的实体不是常量表达式的允许结果 [表达式常量]/8 :

    实体是 常数表达式的允许结果 如果它是一个具有静态存储持续时间的对象,不是临时对象,或者是一个值满足上述约束的临时对象,又或者它是一种非立即函数。

    所讨论的对象既不是静态存储持续时间,也不是临时对象…