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