Home > OS >  What is the best place for a static_assert?
What is the best place for a static_assert?

Time:03-25

Consider the following code:

#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() {
}

I get the following error:

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

It seems, if I move the static_assert outside the class then it compiles fine but inside the class it does not. Conversely, if the class has a template type then the reverse is true.

Why am I getting the error here and why do I not get it when DeepNodeIter is a template class?

CodePudding user response:

It doesn't actually compile when you make DeepNodeIter a template either: https://godbolt.org/z/W9jf94xPn

The reason it may have looked like it worked is if you did not instantiate the template, the compiler will not proactively fail to compile since you might specialize the template before you instantiate it.

The reason this does not work is, a type is considered incomplete until it's closing brace is reached. Until then, it is as if you only have a declaration of the type, i.e. class DeepNodeIter;. There are exceptions to this rule like member functions defined within the definition being compiled as if they were right after the class definition, but apparently not for static_asserts.

  • Related