|  | Home | Libraries | People | FAQ | More | 
Copyright © 2016, 2017 Barrett Adair
Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.md or copy at http://www.boost.org/LICENSE_1_0.txt)
Table of Contents
      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.
    
#include <type_traits> #include <tuple> #include <boost/callable_traits.hpp> namespace ct = boost::callable_traits; // This function template helps keep our example code neat template<typename A, typename B> void assert_same(){ static_assert(std::is_same<A, B>::value, ""); } // foo is a function object struct foo { void operator()(int, char, float) const {} }; int main() { // Use args_t to retrieve a parameter list as a std::tuple: assert_same< ct::args_t<foo>, std::tuple<int, char, float> >(); // has_void_return lets us perform a quick check for a void return type static_assert(ct::has_void_return<foo>::value, ""); // Detect C-style variadics (ellipses) in a signature (e.g. printf) static_assert(!ct::has_varargs<foo>::value, ""); // pmf is a pointer-to-member function: void (foo::*)(int, char, float) const using pmf = decltype(&foo::operator()); // remove_member_const_t lets you remove the const member qualifier assert_same< ct::remove_member_const_t<pmf>, void (foo::*)(int, char, float) /*no const!*/ >(); // Conversely, add_member_const_t adds a const member qualifier assert_same< pmf, ct::add_member_const_t<void (foo::*)(int, char, float)> >(); // is_const_member_v checks for the presence of member const static_assert(ct::is_const_member<pmf>::value, ""); }
“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 24 template specializations necessary to account for all the function types in C++11:
template<typename T> struct foo; //function type without varargs 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 &&> {}; //function type with varargs 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 &&> {};
        Things get even more complicated with member function pointers, function
        pointers, function references, function objects, and transaction_safe/noexcept.
      
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 very specific metaprogramming scenarios that can only be solved with this kind of template "spam". Writing and testing these templates is tedious and time consuming, and often requires lots of code duplication.
        Boost.CallableTraits offers a final and decisive library-level
        solution to this problem, and removes the need for these specializations
        entirely (except for platform-specific calling conventions).
      
        The features in Boost.CallableTraits largely overlap with
        Boost.FunctionTypes.
        Here are some reasons why you might prefer Boost.CallableTraits:
      
Boost.FunctionTypes is tightly coupled to Boost.MPL
            sequences, while Boost.CallableTraits has no dependencies
            other than the standard library.
          Boost.CallableTraits targets C++11 and later:
            Boost.CallableTraits treats function objects/lambdas
                  as first-class citizens.
                Boost.CallableTraits supports lvalue/rvalue
                  reference member qualifiers.
                Boost.CallableTraits supports noexcept and transaction_safe.
                Boost.FunctionTypes does not attempt to factor all
            callable types into a unified, INVOKE-aware
            interface.
          Boost.FunctionTypes relies heavily on "tag"
            types, while Boost.CallableTraits follows the style
            of <type_traits> instead. Supporting C++11 and later in Boost.FunctionTypes
            would have required significant proliferation of these tags.
          
        For example, here is how to remove member const
        from a member function pointer type in the Boost.FunctionTypes
        library:
      
#include <type_traits> #include <boost/function_types/components.hpp> #include <boost/function_types/member_function_pointer.hpp> struct foo { void bar() const {} }; using const_removed = typename boost::function_types::member_function_pointer< typename boost::function_types::components<decltype(&foo::bar)>::types, boost::function_types::non_const>::type; static_assert(std::is_same<const_removed, void(foo::*)()>::value, ""); int main(){}
        Boost.CallableTraits makes this easier:
      
#include <type_traits> #include <boost/callable_traits/remove_member_const.hpp> struct foo { void bar() const {} }; using const_removed = boost::callable_traits::remove_member_const_t<decltype(&foo::bar)>; static_assert(std::is_same<const_removed, void(foo::*)()>::value, ""); int main(){}
        The Boost.FunctionTypes library includes an excellent
        example
        for generating type-erased interfaces (implementation here).
        This example was re-implemented
        using Boost.CallableTraits to yield a slightly
        more intuitive interface.
      
        Boost.FunctionTypes is a fine library, but its interface
        left room for improvement.
      
        Boost.CallableTraits is tested on GCC 4.7.4 and later,
        Clang 3.5.2 and later, XCode 6.4 and later, and Visual Studio 2015. Continuous
        integration is managed on Appveyor
        for Visual Studio, and on Travis
        for everything else. The Intel C++ Compiler is not officially supported,
        although the 2017 version for Linux does pass a handful of test cases.
      
Table 1. GCC Support
| feature | GCC 7.1.0 | GCC 6.3.0 | GCC 5.4.0 | GCC 4.9.2 | GCC 4.8.2 | GCC 4.7.4 | 
|---|---|---|---|---|---|---|
| c++11 | c++11 | c++11 | c++11 | c++11 (no abominables) | c++11 (no abominables) | |
| c++11 | c++11 | c++11 | c++11 | c++11 (no abominables) | c++11 (no abominables) | |
| c++11 | c++11 | c++11 | c++11 | static_assert fails on instantiation | static_assert fails on instantiation | |
| c++11 | c++11 | c++11 | c++11 | static_assert fails on instantiation | static_assert fails on instantiation | |
| c++11 | c++11 | c++11 | c++11 | c++11 (no abominables) | c++11 (no abominables) | |
| c++17 | c++17 | static_assert fails on instantiation | static_assert fails on instantiation | static_assert fails on instantiation | static_assert fails on instantiation | |
| c++17 (requires -fgnu-tm) | c++17 (requires -fgnu-tm) | static_assert fails on instantiation | static_assert fails on instantiation | static_assert fails on instantiation | static_assert fails on instantiation | |
| c++11 | c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 (no abominables) | c++11 (no abominables) | |
| c++11 | c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 (no abominables) | c++11 (no abominables) | |
| c++11 | c++11 | c++11 | c++11 | c++11 (no abominables) | c++11 (no abominables) | |
| c++11 | c++11 | c++11 | c++11 | unknown | unknown | |
| c++11 | c++11 | c++11 | c++11 | c++11 (always false) | c++11 (always false) | |
| c++17 | c++17 | c++11 (always false) | c++11 (always false) | c++11 (always false) | c++11 (always false) | |
| c++11 | c++11 | c++11 | c++11 | c++11 (always false) | c++11 (always false) | |
| c++11 | c++11 | c++11 | c++11 | c++11 (always false) | c++11 (always false) | |
| c++17 (requires -fgnu-tm) | c++17 (requires -fgnu-tm) | c++11 (always false) | c++11 (always false) | c++11 (always false) | c++11 (always false) | |
| c++11 | c++11 | c++11 | c++11 | c++11 (no abominables) | c++11 (no abominables) | |
| c++11 | c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 (no abominables) | c++11 (no abominables) | |
| c++11 | c++11 | c++11 | c++11 | c++11 (no abominables) | c++11 (no abominables) | |
| c++11 | c++11 | c++11 | c++11 | c++11 (no effect) | c++11 (no effect) | |
| c++11 | c++11 | c++11 | c++11 | c++11 (no abominables) | c++11 (no abominables) | |
| c++17 | c++17 | c++11 (no effect) | c++11 (no effect) | c++11 (no effect) | c++11 (no effect) | |
| c++17 (requires -fgnu-tm) | c++17 (requires -fgnu-tm) | c++11 (no effect) | c++11 (no effect) | c++11 (no effect) | c++11 (no effect) | |
| c++11 | c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | c++11 | 
Table 2. LLVM/Clang Support
| feature | Clang 4.0.0 | Clang 3.8.0 | Clang 3.7.1 | Clang 3.6.2 | Clang 3.5.2 | 
|---|---|---|---|---|---|
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++17 | static_assert fails on instantiation | static_assert fails on instantiation | static_assert fails on instantiation | static_assert fails on instantiation | |
| unknown | static_assert fails on instantiation | static_assert fails on instantiation | static_assert fails on instantiation | static_assert fails on instantiation | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++17 | c++11 (always false) | c++11 (always false) | c++11 (always false) | c++11 (always false) | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| unknown | c++11 (always false) | c++11 (always false) | c++11 (always false) | c++11 (always false) | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++17 | c++11 (no effect) | c++11 (no effect) | c++11 (no effect) | c++11 (no effect) | |
| unknown | c++11 (no effect) | c++11 (no effect) | c++11 (no effect) | c++11 (no effect) | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | 
Table 3. XCode/AppleClang Support
| feature | XCode 8 | XCode 7.3 | XCode 7.2 | XCode 7.1 | XCode 6.4 | 
|---|---|---|---|---|---|
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| unknown | static_assert fails on instantiation | static_assert fails on instantiation | static_assert fails on instantiation | static_assert fails on instantiation | |
| unknown | static_assert fails on instantiation | static_assert fails on instantiation | static_assert fails on instantiation | static_assert fails on instantiation | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| unknown | c++11 (always false) | c++11 (always false) | c++11 (always false) | c++11 (always false) | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| unknown | c++11 (always false) | c++11 (always false) | c++11 (always false) | c++11 (always false) | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| unknown | c++11 (no effect) | c++11 (no effect) | c++11 (no effect) | c++11 (no effect) | |
| unknown | c++11 (no effect) | c++11 (no effect) | c++11 (no effect) | c++11 (no effect) | |
| c++11 | c++11 | c++11 | c++11 | c++11 | |
| c++11 | c++11 | c++11 | c++11 | c++11 | 
Table 4. Visual Studio Support
| feature | MSVC with Visual Studio 2017 | MSVC with Visual Studio 2015 (latest update) | 
|---|---|---|
| c++11 | c++11 | |
| c++11 | c++11 | |
| c++11 | c++11 | |
| c++11 | c++11 | |
| c++11 | c++11 | |
| static_assert fails on instantiation | static_assert fails on instantiation | |
| static_assert fails on instantiation | static_assert fails on instantiation | |
| c++11 (define BOOST_DISABLE_WIN32 to disable __cdecl on PMF varargs) | c++11 (define BOOST_DISABLE_WIN32 to disable __cdecl on PMF varargs) | |
| c++11 | c++11 | |
| c++11 | c++11 | |
| c++11 | c++11 | |
| c++11 | c++11 | |
| c++11 | c++11 | |
| c++11 | c++11 | |
| c++11 (define BOOST_DISABLE_WIN32 to disable __cdecl on PMF varargs) | c++11 (define BOOST_DISABLE_WIN32 to disable __cdecl on PMF varargs) | |
| c++11 | c++11 | |
| c++11 | c++11 | |
| c++11 | c++11 | |
| c++11 | c++11 (always false for functions that are simultaneously ref and cv-qualified due to compiler bug) | |
| c++11 | c++11 | |
| c++11 (always false) | c++11 (always false) | |
| c++11 | c++11 | |
| c++11 | c++11 | |
| c++11 (always false) | c++11 (always false) | |
| c++11 | c++11 | |
| c++11 | c++11 | |
| c++11 | c++11 | |
| c++11 | c++11 | |
| c++11 | c++11 | |
| c++11 | c++11 | |
| c++11 (no effect) | c++11 (no effect) | |
| c++11 (no effect) | c++11 (no effect) | |
| c++11 (define BOOST_DISABLE_WIN32 to disable __cdecl on PMF varargs) | c++11 (define BOOST_DISABLE_WIN32 to disable __cdecl on PMF varargs) | |
| c++11 | c++11 |