Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

What is the best place for a static_assert?

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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

>Solution :

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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading