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

时间:2019-08-31 10:09:05

标签: c++ c++11 language-lawyer constexpr static-assert

#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'

1 个答案:

答案 0 :(得分:10)

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

  

表达式e是核心常量表达式 除非 e 的求值,按照抽象机的规则,将求出其中一个以下表达式:

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

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

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

第二种情况之所以编译,是因为它不涉及非常数的lvalue-to-rvalue conversionsizeof(n)实际上没有“读取” n)。

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

struct A
{
    int n;

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

注意:如果引用的生命周期始于{{3},则在constexpr上下文(Types&&部分)内本身不会破坏“ constexpr-ness”。 }}。

另一个例子:

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