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

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:

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

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

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

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

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

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

c++17

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 3. XCode/AppleClang Support

feature

XCode 8

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