【问题标题】:Why can't I get the argument count of a template function at compile-time?为什么我不能在编译时获得模板函数的参数计数?
【发布时间】:2020-01-04 07:36:13
【问题描述】:
#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'

【问题讨论】:

  • 看来你得把数据成员设为nconstexpr
  • 注意主体没问题,其中n也不是constexpr。
  • 我不确定;涉及this 指针时,事情变得复杂。
  • 由于某种原因,如果将int n = this-&gt;n; 添加到f(),第一个断言也可以正常工作。
  • 它也适用于A().n&amp;A::n,但不适用于std::declval&lt;A&gt;().n

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


【解决方案1】:

constexpr 上下文之外访问this 的任何内容不是一个常量表达式,如[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`
    }
};

注意:在 constexpr 上下文(Types&amp;&amp; 部分)中拥有引用本身不会破坏“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

【讨论】:

  • 大概就是这样。这解释了为什么 int n = 1; static_assert(getArgCount(&amp;n)); 确实有效(即使 &amp;n 不是 constexpr,也没有左值到右值的转换)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-23
  • 1970-01-01
  • 1970-01-01
  • 2019-11-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多