Boost C++ Libraries Home Libraries People FAQ More

Next

CallableTraits

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

Overview
Motivation
Regarding Boost.FunctionTypes
Compatibility
Reference Documentation
add_member_const
add_member_cv
add_member_lvalue_reference
add_member_rvalue_reference
add_member_volatile
add_noexcept
add_transaction_safe
add_varargs
apply_member_pointer
apply_return
args
class_of
function_type
has_member_qualifiers
has_varargs
has_void_return
is_const_member
is_cv_member
is_invocable
is_lvalue_reference_member
is_reference_member
is_rvalue_reference_member
is_noexcept
is_transaction_safe
is_volatile_member
qualified_class_of
remove_member_const
remove_member_cv
remove_member_reference
remove_member_volatile
remove_noexcept
remove_transaction_safe
remove_varargs
return_type
FAQ
Building the test suite
Contact
Acknowledgements

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 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.

Boost.CallableTraits offers a final and decisive library-level solution to this problem, and removes the need for these specializations entirely (platform-specific calling conventions notwithstanding).

The features in Boost.CallableTraits largely overlap with Boost.FunctionTypes. Here are some reasons why you might prefer Boost.CallableTraits:

  1. Boost.FunctionTypes is tightly coupled to Boost.MPL sequences, while Boost.CallableTraits has no dependencies other than the standard library.
  2. Boost.CallableTraits targets C++11 and later:
    1. Boost.CallableTraits treats function objects/lambdas as first-class citizens.
    2. Boost.CallableTraits supports lvalue/rvalue reference member qualifiers.
    3. Boost.CallableTraits supports noexcept and transaction_safe.
  3. Boost.FunctionTypes does not attempt to factor all callable types into a unified, INVOKE-aware interface.
  4. 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 supports on GCC 4.7.4+, Clang 3.5.2+, XCode 6.4+, and Visual Studio 2015+. 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.3.0 and later

GCC 6.3.0

GCC 5.4.0

GCC 4.9.2

GCC 4.8.2

GCC 4.7.4

add_member_const

c++11

c++11

c++11

c++11

c++11 (no abominables)

c++11 (no abominables)

add_member_cv

c++11

c++11

c++11

c++11

c++11 (no abominables)

c++11 (no abominables)

add_member_lvalue_reference

c++11

c++11

c++11

c++11

static_assert fails on instantiation

static_assert fails on instantiation

add_member_rvalue_reference

c++11

c++11

c++11

c++11

static_assert fails on instantiation

static_assert fails on instantiation

add_member_volatile

c++11

c++11

c++11

c++11

c++11 (no abominables)

c++11 (no abominables)

add_noexcept

c++17

c++17

static_assert fails on instantiation

static_assert fails on instantiation

static_assert fails on instantiation

static_assert fails on instantiation

add_transaction_safe

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

add_varargs

c++11

c++11

c++11

c++11

c++11

c++11

apply_member_pointer

c++11

c++11

c++11

c++11

c++11

c++11

apply_return

c++11

c++11

c++11

c++11

c++11

c++11

args

c++11

c++11

c++11

c++11

c++11

c++11

class_of

c++11

c++11

c++11

c++11

c++11

c++11

function_type

c++11

c++11

c++11

c++11

c++11

c++11

has_member_qualifiers

c++11

c++11

c++11

c++11

c++11 (no abominables)

c++11 (no abominables)

has_varargs

c++11

c++11

c++11

c++11

c++11

c++11

has_void_return

c++11

c++11

c++11

c++11

c++11

c++11

is_const_member

c++11

c++11

c++11

c++11

c++11 (no abominables)

c++11 (no abominables)

is_cv_member

c++11

c++11

c++11

c++11

c++11 (no abominables)

c++11 (no abominables)

is_invocable

c++11

c++11

c++11

c++11

unknown

unknown

is_lvalue_reference_member

c++11

c++11

c++11

c++11

c++11 (always false)

c++11 (always false)

is_noexcept

c++17

c++17

c++11 (always false)

c++11 (always false)

c++11 (always false)

c++11 (always false)

is_reference_member

c++11

c++11

c++11

c++11

c++11 (always false)

c++11 (always false)

is_rvalue_reference_member

c++11

c++11

c++11

c++11

c++11 (always false)

c++11 (always false)

is_transaction_safe

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)

is_volatile_member

c++11

c++11

c++11

c++11

c++11 (no abominables)

c++11 (no abominables)

qualified_class_of

c++11

c++11

c++11

c++11

c++11

c++11

remove_member_const

c++11

c++11

c++11

c++11

c++11 (no abominables)

c++11 (no abominables)

remove_member_cv

c++11

c++11

c++11

c++11

c++11 (no abominables)

c++11 (no abominables)

remove_member_reference

c++11

c++11

c++11

c++11

c++11 (no effect)

c++11 (no effect)

remove_member_volatile

c++11

c++11

c++11

c++11

c++11 (no abominables)

c++11 (no abominables)

remove_noexcept

c++17

c++17

c++11 (no effect)

c++11 (no effect)

c++11 (no effect)

c++11 (no effect)

remove_transaction_safe

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)

remove_varargs

c++11

c++11

c++11

c++11

c++11

c++11

return_type

c++11

c++11

c++11

c++11

c++11

c++11


Table 2. LLVM/Clang Support

feature

Clang 4.0.0 and later

Clang 3.8.0

Clang 3.7.1

Clang 3.6.2

Clang 3.5.2

add_member_const

c++11

c++11

c++11

c++11

c++11

add_member_cv

c++11

c++11

c++11

c++11

c++11

add_member_lvalue_reference

c++11

c++11

c++11

c++11

c++11

add_member_rvalue_reference

c++11

c++11

c++11

c++11

c++11

add_member_volatile

c++11

c++11

c++11

c++11

c++11

add_noexcept

c++17

static_assert fails on instantiation

static_assert fails on instantiation

static_assert fails on instantiation

static_assert fails on instantiation

add_transaction_safe

static_assert fails on instantiation

static_assert fails on instantiation

static_assert fails on instantiation

static_assert fails on instantiation

static_assert fails on instantiation

add_varargs

c++11

c++11

c++11

c++11

c++11

apply_member_pointer

c++11

c++11

c++11

c++11

c++11

apply_return

c++11

c++11

c++11

c++11

c++11

args

c++11

c++11

c++11

c++11

c++11

class_of

c++11

c++11

c++11

c++11

c++11

function_type

c++11

c++11

c++11

c++11

c++11

has_member_qualifiers

c++11

c++11

c++11

c++11

c++11

has_varargs

c++11

c++11

c++11

c++11

c++11

has_void_return

c++11

c++11

c++11

c++11

c++11

is_const_member

c++11

c++11

c++11

c++11

c++11

is_cv_member

c++11

c++11

c++11

c++11

c++11

is_invocable

c++11

c++11

c++11

c++11

c++11

is_lvalue_reference_member

c++11

c++11

c++11

c++11

c++11

is_noexcept

c++17

c++11 (always false)

c++11 (always false)

c++11 (always false)

c++11 (always false)

is_reference_member

c++11

c++11

c++11

c++11

c++11

is_rvalue_reference_member

c++11

c++11

c++11

c++11

c++11

is_transaction_safe

c++11 (always false)

c++11 (always false)

c++11 (always false)

c++11 (always false)

c++11 (always false)

is_volatile_member

c++11

c++11

c++11

c++11

c++11

qualified_class_of

c++11

c++11

c++11

c++11

c++11

remove_member_const

c++11

c++11

c++11

c++11

c++11

remove_member_cv

c++11

c++11

c++11

c++11

c++11

remove_member_reference

c++11

c++11

c++11

c++11

c++11

remove_member_volatile

c++11

c++11

c++11

c++11

c++11

remove_noexcept

c++17

c++11 (no effect)

c++11 (no effect)

c++11 (no effect)

c++11 (no effect)

remove_transaction_safe

c++11 (no effect)

c++11 (no effect)

c++11 (no effect)

c++11 (no effect)

c++11 (no effect)

remove_varargs

c++11

c++11

c++11

c++11

c++11

return_type

c++11

c++11

c++11

c++11

c++11


Table 3. XCode/AppleClang Support

feature

XCode 8 and later

XCode 7.3

XCode 7.2

XCode 7.1

XCode 6.4

add_member_const

c++11

c++11

c++11

c++11

c++11

add_member_cv

c++11

c++11

c++11

c++11

c++11

add_member_lvalue_reference

c++11

c++11

c++11

c++11

c++11

add_member_rvalue_reference

c++11

c++11

c++11

c++11

c++11

add_member_volatile

c++11

c++11

c++11

c++11

c++11

add_noexcept

unknown

static_assert fails on instantiation

static_assert fails on instantiation

static_assert fails on instantiation

static_assert fails on instantiation

add_transaction_safe

unknown

static_assert fails on instantiation

static_assert fails on instantiation

static_assert fails on instantiation

static_assert fails on instantiation

add_varargs

c++11

c++11

c++11

c++11

c++11

apply_member_pointer

c++11

c++11

c++11

c++11

c++11

apply_return

c++11

c++11

c++11

c++11

c++11

args

c++11

c++11

c++11

c++11

c++11

class_of

c++11

c++11

c++11

c++11

c++11

function_type

c++11

c++11

c++11

c++11

c++11

has_member_qualifiers

c++11

c++11

c++11

c++11

c++11

has_varargs

c++11

c++11

c++11

c++11

c++11

has_void_return

c++11

c++11

c++11

c++11

c++11

is_const_member

c++11

c++11

c++11

c++11

c++11

is_cv_member

c++11

c++11

c++11

c++11

c++11

is_invocable

c++11

c++11

c++11

c++11

c++11

is_lvalue_reference_member

c++11

c++11

c++11

c++11

c++11

is_noexcept

unknown

c++11 (always false)

c++11 (always false)

c++11 (always false)

c++11 (always false)

is_reference_member

c++11

c++11

c++11

c++11

c++11

is_rvalue_reference_member

c++11

c++11

c++11

c++11

c++11

is_transaction_safe

unknown

c++11 (always false)

c++11 (always false)

c++11 (always false)

c++11 (always false)

is_volatile_member

c++11

c++11

c++11

c++11

c++11

qualified_class_of

c++11

c++11

c++11

c++11

c++11

remove_member_const

c++11

c++11

c++11

c++11

c++11

remove_member_cv

c++11

c++11

c++11

c++11

c++11

remove_member_reference

c++11

c++11

c++11

c++11

c++11

remove_member_volatile

c++11

c++11

c++11

c++11

c++11

remove_noexcept

unknown

c++11 (no effect)

c++11 (no effect)

c++11 (no effect)

c++11 (no effect)

remove_transaction_safe

unknown

c++11 (no effect)

c++11 (no effect)

c++11 (no effect)

c++11 (no effect)

remove_varargs

c++11

c++11

c++11

c++11

c++11

return_type

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)

add_member_const

c++11

c++11

add_member_cv

c++11

c++11

add_member_lvalue_reference

c++11

c++11

add_member_rvalue_reference

c++11

c++11

add_member_volatile

c++11

c++11

add_noexcept

static_assert fails on instantiation

static_assert fails on instantiation

add_transaction_safe

static_assert fails on instantiation

static_assert fails on instantiation

add_varargs

c++11 (define BOOST_DISABLE_WIN32 to disable __cdecl on PMF varargs)

c++11 (define BOOST_DISABLE_WIN32 to disable __cdecl on PMF varargs)

apply_member_pointer

c++11

c++11

apply_return

c++11

c++11

args

c++11

c++11

class_of

c++11

c++11

function_type

c++11

c++11

has_member_qualifiers

c++11

c++11

has_varargs

c++11 (define BOOST_DISABLE_WIN32 to disable __cdecl on PMF varargs)

c++11 (define BOOST_DISABLE_WIN32 to disable __cdecl on PMF varargs)

has_void_return

c++11

c++11

is_const_member

c++11

c++11

is_cv_member

c++11

c++11

is_invocable

c++11

c++11 (always false for functions that are simultaneously ref and cv-qualified due to compiler bug)

is_lvalue_reference_member

c++11

c++11

is_noexcept

c++11 (always false)

c++11 (always false)

is_reference_member

c++11

c++11

is_rvalue_reference_member

c++11

c++11

is_transaction_safe

c++11 (always false)

c++11 (always false)

is_volatile_member

c++11

c++11

qualified_class_of

c++11

c++11

remove_member_const

c++11

c++11

remove_member_cv

c++11

c++11

remove_member_reference

c++11

c++11

remove_member_volatile

c++11

c++11

remove_noexcept

c++11 (no effect)

c++11 (no effect)

remove_transaction_safe

c++11 (no effect)

c++11 (no effect)

remove_varargs

c++11 (define BOOST_DISABLE_WIN32 to disable __cdecl on PMF varargs)

c++11 (define BOOST_DISABLE_WIN32 to disable __cdecl on PMF varargs)

return_type

c++11

c++11



Next