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

xml*_*lmx 12 c++ static-assert language-lawyer constexpr c++11

#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
}
Run Code Online (Sandbox Code Playgroud)

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

错误信息:

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'
Run Code Online (Sandbox Code Playgroud)

rus*_*tyx 10

任何访问this外部constexpr上下文的内容都不[expr.const] /2.1中定义的常量表达式:

表达式e是一个核心常量表达式 除非的评价Ë,以下抽象机的规则,将评估下列表达式之一:

  • this,但作为e的一部分的constexpr函数或constexpr构造函数除外;

(我们需要this访问n才能getArgCount通过引用传递给它)

这就是为什么第一种情况不编译的原因。

第二种情况之所以编译,是因为它不涉及非常数的lvalue到rvalue的转换sizeof(n)实际上并不“读取” n)。

为了说明这一点,还将编译以下内容:

struct A
{
    int n;

    void f()
    {
        int m = n;
        static_assert(getArgCount(m) > 0); // ok, m doesn't need `this`
    }
};
Run Code Online (Sandbox Code Playgroud)

注意:如果引用的生存期在该上下文中开始,则其本身在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)
    }
};
Run Code Online (Sandbox Code Playgroud)

以下内容无法编译:

    int n = 1;
    static_assert(getArgCount(n+1) > 0); // not ok, (n+1) "reads" n
Run Code Online (Sandbox Code Playgroud)