Boost.CallableTraits is a C++11 header-only library for the inspection, synthesis, and decomposition of callable types. Boost.CallableTraits aims to be the "complete type manipulation facility for function types" mentioned in the final paragraph of C++17 proposal p0172, and removes the need for template specializations for different function signatures. C++17 noexcept and the Transactional Memory TS are also supported if available.

“Don't try to write helper code to detect PMFs/PMDs and dispatch on them -- it is an absolute nightmare. PMF types are the worst types by far in the core language.” -- Stephan T. Lavavej, CppCon 2015, "functional: What's New, And Proper Usage"

Consider for a moment the code below, which defines all 48 template specializations necessary to specialize for every valid function type in pure C++17:

template < typename T > struct foo ; template < class Return , class ... Args > struct foo < Return ( Args ...)> {}; template < class Return , class ... Args > struct foo < Return ( Args ...) &> {}; template < class Return , class ... Args > struct foo < Return ( Args ...) &&> {}; template < class Return , class ... Args > struct foo < Return ( Args ...) const > {}; template < class Return , class ... Args > struct foo < Return ( Args ...) const &> {}; template < class Return , class ... Args > struct foo < Return ( Args ...) const &&> {}; template < class Return , class ... Args > struct foo < Return ( Args ...) volatile > {}; template < class Return , class ... Args > struct foo < Return ( Args ...) volatile &> {}; template < class Return , class ... Args > struct foo < Return ( Args ...) volatile &&> {}; template < class Return , class ... Args > struct foo < Return ( Args ...) const volatile > {}; template < class Return , class ... Args > struct foo < Return ( Args ...) const volatile &> {}; template < class Return , class ... Args > struct foo < Return ( Args ...) const volatile &&> {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...)> {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) &> {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) &&> {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) const > {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) const &> {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) const &&> {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) volatile > {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) volatile &> {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) volatile &&> {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) const volatile > {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) const volatile &> {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) const volatile &&> {}; template < class Return , class ... Args > struct foo < Return ( Args ...) noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ...) & noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ...) && noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ...) const noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ...) const & noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ...) const && noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ...) volatile noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ...) volatile & noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ...) volatile && noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ...) const volatile noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ...) const volatile & noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ...) const volatile && noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) & noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) && noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) const noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) const & noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) const && noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) volatile noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) volatile & noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) volatile && noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) const volatile noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) const volatile & noexcept > {}; template < class Return , class ... Args > struct foo < Return ( Args ..., ...) const volatile && noexcept > {};

Things get even more complicated with member function pointers, function pointers, function references, function objects, and transaction_safe .

Granted, use cases for such obscure specializations are vitually nonexistent in run-of-the-mill application codebases. Even in library code, these are exceedingly rare. However, there are a handful of metaprogramming scenarios that can only be solved with this kind of template "spam". Writing, testing, and maintaining such code is tedious and costly.