3rdParty/boost/1.78.0/libs/callable_traits/doc/html/index.html
| | Home | Libraries | People | FAQ | More |
Copyright © 2016-2021 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)
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\>namespacect=boost::callable\_traits;// This function template helps keep our example code neattemplate\<typenameA,typenameB\>voidassert\_same(){static\_assert(std::is\_same\<A,B\>::value,"");}// foo is a function objectstructfoo{voidoperator()(int,char,float)const{}};intmain(){// 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 typestatic\_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) constusingpmf=decltype(&foo::operator());// remove\_member\_const\_t lets you remove the const member qualifierassert\_same\<ct::remove\_member\_const\_t\<pmf\>,void(foo::\*)(int,char,float)/\*no const!\*/\>();// Conversely, add\_member\_const\_t adds a const member qualifierassert\_same\<pmf,ct::add\_member\_const\_t\<void(foo::\*)(int,char,float)\>\>();// is\_const\_member\_v checks for the presence of member conststatic\_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\<typenameT\>structfoo;template\<classReturn,class...Args\>structfoo\<Return(Args...)\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)&\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)&&\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)const\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)const&\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)const&&\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)volatile\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)volatile&\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)volatile&&\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)constvolatile\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)constvolatile&\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)constvolatile&&\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)&\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)&&\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)const\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)const&\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)const&&\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)volatile\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)volatile&\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)volatile&&\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)constvolatile\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)constvolatile&\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)constvolatile&&\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)&noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)&&noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)constnoexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)const&noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)const&&noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)volatilenoexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)volatile&noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)volatile&&noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)constvolatilenoexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)constvolatile&noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...)constvolatile&&noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)&noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)&&noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)constnoexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)const&noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)const&&noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)volatilenoexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)volatile&noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)volatile&&noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)constvolatilenoexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)constvolatile&noexcept\>{};template\<classReturn,class...Args\>structfoo\<Return(Args...,...)constvolatile&&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).
Boost.FunctionTypesThe 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\>structfoo{voidbar()const{}};usingconst\_removed=typenameboost::function\_types::member\_function\_pointer\<typenameboost::function\_types::components\<decltype(&foo::bar)\>::types,boost::function\_types::non\_const\>::type;static\_assert(std::is\_same\<const\_removed,void(foo::\*)()\>::value,"");intmain(){}
Boost.CallableTraits makes this easier:
#include\<type\_traits\>#include\<boost/callable\_traits/remove\_member\_const.hpp\>structfoo{voidbar()const{}};usingconst\_removed=boost::callable\_traits::remove\_member\_const\_t\<decltype(&foo::bar)\>;static\_assert(std::is\_same\<const\_removed,void(foo::\*)()\>::value,"");intmain(){}
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
| | --- | --- | --- | --- | --- | --- | --- | |
|
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 and later
|
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
| |
|
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
| |
|
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
| |
|
c++11 (always false)
|
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)
| |
|
c++11 (no effect)
|
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 and later
|
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
|
| |
|