static_assert 的最佳去处是什么?

What is the best place for a static_assert?

考虑以下代码:

#include <iterator>

struct Node {
  static Node mNode;
};

Node Node::mNode;

struct DeepNodeRange {};

class DeepNodeIter
{
public:
  using iterator_category = std::forward_iterator_tag;
  using value_type = Node*;
  using difference_type = std::ptrdiff_t;

  DeepNodeIter() = default;

  DeepNodeIter(DeepNodeRange& deepNodeRange, bool end = false) :
    mDeepNodeRange(&deepNodeRange), mEnd(end) {}

  Node* operator*() const { return &Node::mNode; }

  DeepNodeIter& operator++()
  {
    mIdx++;
    mEnd = (mIdx > 10);

    return *this;
  }

  DeepNodeIter operator++([[maybe_unused]] int val)
  {
    auto tmp(*this);
    operator++();

    return tmp;
  }

bool operator==(const DeepNodeIter& iter) const { return iter.mEnd == mEnd; }

protected:
  DeepNodeRange* mDeepNodeRange;

  int mIdx;

  bool mEnd;

  static_assert(std::forward_iterator<DeepNodeIter>);
};    

int main() {
}

我收到以下错误:

In file included from include/c++/11.1.0/bits/stl_iterator_base_types.h:67,
                 from include/c++/11.1.0/iterator:61,
                 from b.cpp:1:include/c++/11.1.0/type_traits: In instantiation of 'struct std::is_nothrow_destructible<DeepNodeIter>':
include/c++/11.1.0/type_traits:3166:35:   required from 'constexpr const bool std::is_nothrow_destructible_v<DeepNodeIter>'
include/c++/11.1.0/concepts:134:28:   required from here
include/c++/11.1.0/type_traits:900:52: error: static assertion failed: template argument must be a complete class or an unbounded array
  900 |       static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
      |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
include/c++/11.1.0/type_traits:900:52: note: 'std::__is_complete_or_unbounded<std::__type_identity<DeepNodeIter> >((std::__type_identity<DeepNodeIter>{}, std::__type_identity<DeepNodeIter>()))' evaluates to false
b.cpp:50:22: error: static assertion failed
   50 |   static_assert(std::forward_iterator<DeepNodeIter>);
      |                 ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
b.cpp:50:22: note: constraints not satisfied

看来,如果我将 static_assert 移到 class 之外,那么它可以正常编译,但在 class 内部则不能。相反,如果 class 具有模板类型,则反之亦然。

为什么我在这里收到错误消息,为什么当 DeepNodeIter 是模板 class 时我没有收到错误消息?

当你制作 DeepNodeIter 模板时它实际上并没有编译:https://godbolt.org/z/W9jf94xPn

它看起来有效的原因是,如果您没有实例化模板,编译器将不会主动编译失败,因为您可能会在实例化之前专门化模板。

这不起作用的原因是,一个类型在到达它的右大括号之前被认为是不完整的。在那之前,就好像你只有一个类型的声明,即 class DeepNodeIter;。此规则有一些例外情况,例如定义中定义的成员函数被编译为就好像它们就在 class 定义之后,但显然不是 static_asserts.