有人可以解释为什么下面标记的行编译得很好:
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
本身并非如此,我不明白它为什么会起作用。
答案 0 :(得分: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函数的评估方法。除了其他功能之外,您还可以使用if语句,constexpr函数中的文字类型的语句和局部变量。
答案 1 :(得分:2)
您的问题和评论:
我想我很困惑,为什么地址未知的自动变量可以通过引用常量表达式中使用的函数来传递
当编译器看到get_size(xs)
时,它已经解析了前一行int xs[10];
,因此知道xs
的类型和大小。在类型和 size 方面, nothing 在运行时会发生变化,这两个是编译所需的信息为了实例化函数模板,所以它没有遇到任何实例化函数模板的问题,在这种情况下它表现为constexpr
,因为在编译时一切都是已知的,这就是为什么static_assert
不会失败。