为什么在编译时无法获取模板函数的参数计数?

Why can't I get the argument count of a template function at compile-time?

本文关键字:函数 参数 编译 获取 为什么      更新时间:2023-10-16
#include <cstddef>
template<typename... Types>
constexpr std::size_t getArgCount(Types&&...) noexcept
{
return sizeof...(Types);
}
struct A
{
int n;
void f()
{
static_assert(getArgCount(n) > 0); // not ok, why?
}
};
int main()
{
int n;
static_assert(getArgCount(n) > 0); // ok
}

为什么在编译时无法获取模板函数的参数计数?

错误信息:

1>test.cpp
1>test.cpp(17,45): error C2131:  expression did not evaluate to a constant
1>test.cpp(17,42): message :  failure was caused by a read of a variable outside its lifetime
1>test.cpp(17,42): message :  see usage of 'this'

任何在上下文constexpr之外访问this的东西都不是常量表达式,如 [expr.const]/2.1 中所定义:

表达式 e 是核心常量表达式,除非e的计算遵循抽象机器的规则,将计算以下表达式之一:

  • this,除了在constexpr函数或作为e的一部分被评估的constexpr构造函数中;

(我们需要this才能访问n,以便通过引用将其传递给getArgCount(

所以这就是为什么第一种情况无法编译的原因。

第二种情况是编译的,因为它不涉及非常量的左值到右值转换(sizeof(n)实际上并没有"读取"n(。

为了演示这一点,还将编译以下内容:

struct A
{
int n;
void f()
{
int m = n;
static_assert(getArgCount(m) > 0); // ok, m doesn't need `this`
}
};

注意:如果引用的生存期始于该上下文,则在constexpr上下文(Types&&部分(中具有引用本身不会破坏"constexpr-ness":[expr.const]/2.11.2。

再比如:

struct A
{
int n;
void f()
{
static_assert(sizeof(n) > 0); // ok, don't need this for sizeof(A::n)
}
};

以下内容无法编译:

int n = 1;
static_assert(getArgCount(n+1) > 0); // not ok, (n+1) "reads" n