title: Using static_assert() to provide better compile-time errors (than the compilers)
body: <p>Yesterday it took me ages to come to grips with a compile-time error caused by calling a <code>const</code> member function from a non-<code>const</code> object as in this example:</p>
  
  <pre><code>// my utility header
  template&lt;typename derived&gt;
  struct crtp_task : task
  {
    std::list&lt;task*&gt; list;
  
    // note: cannot be const, as task::allocate_child() isn't
    template&lt;typename... Args&gt;      
    void add_child(Args&amp;&amp;... args)
    {
      list.push_back(new(task::allocate_child())
                     derived(std::forward&lt;Args&gt;(args)...));
    }
    /* ... */
  };
  
  // an application
  struct my_task : crtp_task&lt;my_task&gt;
  {
    some_data data;
    /* ... */
    my_task(some_data d) data(d) {}
    void generate_children() const    // constant member
    {
      /* ... */
      some_data child_data = /* ... */;
      this-&gt;add_child(child_data);    // error: cannot call non-const member
    }
  };
  </code></pre>
  
  <p>The clang error message was several lines and too cryptic (not mentioning <code>const</code>), but gcc came up with a better error (though even more lines, but eventually complaining about me ignoring cv qualifiers).</p>
  
  <p>So, to avoid this sort of thing in the future, I thought about using <code>static_assert()</code> in my utility header. My naive approach</p>
  
  <pre><code>// my utility header
  template&lt;typename derived&gt;
  struct crtp_task : task
  {
    std::list&lt;task*&gt; list;
  
    // note: cannot be const, as task::allocate_child() isn't
    template&lt;typename... Args&gt;      
    void add_child(Args&amp;&amp;... args)
    {
      list.push_back(new(task::allocate_child())
                     derived(std::forward&lt;Args&gt;(args)...));
    }
  
    // note: catch call from const objects
    template&lt;typename... Args&gt;      
    void add_child(Args&amp;&amp;...) const
    {
      static_assert(false,"add_child() const called");
    }      
    /* ... */
  };
  </code></pre>
  
  <p>fails, as the compiler immediately triggers an error, even if the template <code>void add_child() const</code> is never called. How else can I make this work?</p>