'How do I add templates to a static_assert?

Consider the following code:

#include <iterator>

struct Node {
  static Node mNode;
};
  
Node Node::mNode;

struct DeepNodeRange {};

template<class T>
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) {}

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

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

    return *this;
  }

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

    return tmp;
    return tmp;
  }

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

protected:
  DeepNodeRange* mDeepNodeRange;

  int mIdx;

  bool mEnd;
};

template<class T>
static_assert(std::forward_iterator<DeepNodeIter<T>>);

int main() {
}                   

I get the following error:

b.cpp:54:1: error: expected unqualified-id before 'static_assert'
   54 | static_assert(std::forward_iterator<DeepNodeIter<T>>);
      | ^~~~~~~~~~~~~
./b.out: Command not found.

I had the static_assert in the class definition before but it was failing because the return types couldn't be deduced to verify the assertion. Now that it's outside, I lack the template definitions I need for the assert to work. Is there a way to get templates in a static_assert?



Solution 1:[1]

C++ templates are Turing-complete. The full description of Foo<T> can involve nearly arbitrary computation in the general case.

Your assert seems to want to assert something uniformly true about all Foo<T>; this is provably impossible in the general case of template type subsitution.

As a rule, C++ will only allow you to invert the mapping implied by Foo<T> in specific narrow cases, and will not let you do universal qualification over it.

TL;DR put the static assert in the type factory.

template<class T>
class DeepNodeIter{
  class DeepNodeIterImpl{ // implement
  };
public:
  using type=DeepNodeIterImpl;
  static_assert(/* blah */);
};
template<class T>
using DeepNodeIter_t=typename DeepNodeIter<T>::type;

that would guarantee a static assert every time you instantiate a DeepNodeIter_t<x>.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Yakk - Adam Nevraumont