4

有人可以解释为什么下面的标记行编译得很好:

template<typename T, int N>
constexpr
int get_size(T (&)[N])
{
    return N;
}

int main()
{
    int xs[10];
    constexpr int y = get_size(xs); // HERE.
    static_assert(10 == y, "wrong size");
}

对我来说,直觉上get_size(xs)不是一个常量表达式,因为xs它本身不是,所以我不明白它为什么起作用。

4

2 回答 2

4

模板函数被实例化后,你的程序就等同于以下内容:

constexpr
int get_size(int (&)[10])
{
    return 10;
}

int main()
{
    int xs[10];
    constexpr int y = get_size(xs); // HERE.
    static_assert(10 == y, "wrong size");
}

然后在函数调用替换之后,它变得等价于以下内容:

int main()
{
    int xs[10];
    constexpr int y = 10; // HERE.
    static_assert(10 == y, "wrong size");
}

函数调用替换在 7.1.5 [dcl.constexpr]/5 中描述。本质上,参数就像复制初始化一样被替换,然后替换为返回表达式中的出现。然后返回表达式同样如同复制初始化返回值一样。然后,生成的表达式将成为替换函数调用的表达式。只有此之后,才考虑表达式是否满足上下文放置的常量表达式的约束。(注意,高质量的编译器当然可以确定 constexpr 函数在任何此类操作后永远无法成功使用,并且在遇到函数定义后可能会失败,但并非必须如此)

另请注意,只是为了让您感到困惑,这个概念在 C++14 中被删除,并替换为如何评估 constexpr 函数的不同概念。除其他外,您将能够在 constexpr 函数中使用 if 语句、for 语句和文字类型的局部变量。

于 2013-10-16T12:57:37.590 回答
2

您的问题和评论:

我想我很困惑为什么地址未知的自动变量可以通过引用来传递给常量表达式中使用的函数

当编译器看到get_size(xs)时,它已经解析了上一行是int xs[10];,因此知道xs. 就类型大小而言,在运行时不会发生任何变化——这两个是编译所需的信息,以便实例化函数模板,因此实例化函数模板不会遇到任何问题,在这种情况下,它的行为就像因为在编译时一切都是已知的,这就是为什么不会失败。constexprstatic_assert

于 2013-10-16T10:45:11.100 回答