Merge remote-tracking branch 'refs/remotes/origin/master' into gh-pages

This commit is contained in:
badair
2016-04-09 17:25:38 -05:00
29 changed files with 1042 additions and 494 deletions

View File

@@ -13,74 +13,178 @@
[lang en]
]
[template library_name[][^CallableTraits]]
[/ Boost developer: you should enable word wrap before you read further]
[template libname[][^CallableTraits]]
[template libns[][^callable_traits::]]
[template header_include_prefix[]callable_traits/]
[template detail_open_include[] `#include<`[^[header_include_prefix]]]
[template detail_close_include[]`.hpp>`]
[template include_header[name][detail_open_include][^[name]][detail_close_include][br]]
[template invoke[][@http://en.cppreference.com/w/cpp/utility/functional/invoke INVOKE]]
[/ *** concepts *** ]
[template fn_obj[][role green FunctionObject]]
[template overloaded_fn_obj[][role green OverloadedFunctionObject]]
[template simple_fn_obj[][role green SimpleFunctionObject]]
[template pmf[][role green MemberFunctionPtr]]
[template pmd[][role green MemberDataPtr]]
[template member_ptr[][role green MemberPtr]]
[template fn[][role green Function]]
[template abominable[][role green AbominableFunction]]
[template fn_ptr[][role green FunctionPtr]]
[template fn_ref[][role green FunctionReference]]
[template simple_callable[][role green SimpleCallable]]
[template simple_invokable[][role green SimpleInvokable]]
[template callable[][role green Callable]]
[template invokable[][role green Invokable]]
[template constexpr_constructible[][role green ConstexprDefaultConstructible]]
[section:introduction Introduction]
[heading Quick Example]
[libname] provides a comprehensive, uniform, and modern type-level interface for the inspection, decomposition, and synthesis of C++ callable types. This documentation will be most beneficial to readers with a basic understanding of the syntax and usage of the following C++ features:
* [@http://en.cppreference.com/w/cpp/language/partial_specialization template specializations]
* [@http://en.cppreference.com/w/cpp/language/sfinae SFINAE]
* [invoke] rules
* function types
* [@http://en.cppreference.com/w/cpp/language/pointer#Pointers_to_functions function pointers]
* [@http://stackoverflow.com/questions/480248/function-references function references]
* [@http://en.cppreference.com/w/cpp/language/pointer#Pointers_to_member_functions pointers to member functions]
* [@http://en.cppreference.com/w/cpp/language/pointer#Pointers_to_data_members pointers to data members]
* [@http://en.cppreference.com/w/cpp/language/operators#Function_call_operator the function call operator, [^operator()]]
* [@https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers universal references] and [@http://stackoverflow.com/questions/13725747/concise-explanation-of-reference-collapsing-rules-requested-1-a-a-2 reference collapsing rules]
* [@http://en.cppreference.com/w/cpp/language/member_functions#const-.2C_volatile-.2C_and_ref-qualified_member_functions cv-qualified and ref-qualified member functions]
* [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0172r0.html "abominable" function types]
* [@http://en.cppreference.com/w/cpp/language/overloaded_address taking the address of an overloaded function]
* [@http://en.cppreference.com/w/c/language/variadic C-style variadics], a.k.a. `varargs`
* [@https://en.wikipedia.org/wiki/X86_calling_conventions calling conventions]
[section Quick Example]
[import ../example/intro.cpp]
[intro]
[endsect]
[section:motivation Motivation]
The complexity of callable types in C++ is extensive:
Several library solutions exist to manipulate functions or callable types. However, none of these are comprehensive, and many of them have not aged well with the advent of modern C++. [libname] fills the gaps found in existing solutions, and improves upon them wherever possible.
*function types
*function pointers
*function references
*objects with `operator()`
*objects with function pointer conversions
*[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0172r0.html "abominable"] function types
*pointers to member data
*pointers to member functions
*qualified overloads of member functions: `const`, `volatile`, `&`, `&&`
*C-style varargs (`...`)
*calling conventions/attributes (`__cdecl`, `__stdcall`, `__fastcall`, `pascal`, etc.)
*[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html [^noexcept]]
Consider for a moment this rather hideous template specialization:
[library_name] provides a comprehensive, uniform, and modern type-level interface for the manipulation and inspection of callable types in C++. By filling the gaps where existing library solutions fall short, [library_name] aims to provide such an exhaustive interface for the features listed above that library writers will *never again* need to specialize templates for callable types. [library_name] eliminates the need for horrific template specializations like these:
template<typename Ret, typename T, typename... Args>
struct foo<Ret(T::*)(Args..., ...) const volatile &&>{
//...
};
[import ./hideous_template.snippet.cpp]
[hideous_template]
Several library solutions exist to manipulate these types, or to abstract away their complexities. However, these solutions are occasionally inflexible or lacking in features, especially regarding function objects/lambdas. In [library_name], function pointers, function references, function types, abominable function types, member function pointers, member data pointers, function objects/lambdas, and references/pointers/smart pointers thereof are generally interchangeable.
Potential use cases for such obscure specializations are vitually nonexistent in run-of-the-mill C++ application codebases. Even in library code, these are exceedingly rare. However, there are a handful of specific problems in C++ that cannot be solved by any other means. While rare, a correct and generic implementation of these templates is tedious and time consuming. [libname] premises that these rare cases necessitate a library solution. One goal of [libname] is to [*completely and decisively eliminate the need for function signature template specializations]. To the knowledge of the author, [libname] is the first and only library solution to attempt this.
The use cases for [library_name] are closely related to those of [@http://www.boost.org/doc/libs/1_60_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html function_traits] and [@http://www.boost.org/doc/libs/1_60_0/libs/function_types/doc/html/index.html FunctionTypes].
The use cases for [libname] are closely related to those of [@http://www.boost.org/doc/libs/1_60_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html function_traits] and [@http://www.boost.org/doc/libs/1_60_0/libs/function_types/doc/html/index.html FunctionTypes].
[important The upcoming C++17 ISO standard brings a language change that adds `noexcept` to signatures. Currently, this is not handled in [library_name], but will be in the future for platforms that support it.]
[important The upcoming C++17 ISO standard includes a [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html change to the core language] which adds [^noexcept] to function signatures. Currently, this is not handled in [libname]. New features to account for this change are planned in [libname], which the author intends to add, with regard for backwards compatibility, as soon as the language change is implemented in a major compiler. ]
[endsect]
[section:ten_reasons 10 reasons to use [library_name]]
[section:basic_concepts Concept Definitions]
# [library_name]' template aliases and `constexpr` `std::integral_constant` functions are preferable to `typename foo::type` and `foo::value`
[heading [fn_ptr]]
* Any function pointer type
* May be cv-qualified and/or ref-qualified
* e.g. `void(*)(int, int)`
# [library_name] offers a familar, consistent interface for the synthesis and decomposition of callable types
* e.g. `remove_function_const` parallels `std::remove_const`
[heading [fn_ref]]
* Any function reference type
* e.g. `void(&)(int, int)`
# universal references are accepted everywhere, so you don't need to worry about using `std::remove_reference` first
[heading [fn]]
* Any unqualified function type
* e.g. `void(int, int)`
# function object pointers/ pointers are accepted (when `INVOKE` is not an immediate concern)
[heading [abominable]]
* Any qualified (a.k.a. [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0172r0.html "abominable"]) function type
* Not technically "callable", but still falls under the [libname] umbrella
* Mutually exclusive with [fn]
* e.g. `void(int, int) const`
# `arg_at<2, Callable>` is better than `typename function_traits<Callable>::arg2_type`
[heading [pmf]]
* Any pointer to member function type
* The pointer type may be cv-qualified and/or ref-qualified
* e.g. `void (foo::*)(int, int)`
# function objects are first-class citizens in [library_name]
* e.g. `result_of` can accept a function object
[heading [pmd]]
* Any pointer to data member type
* The pointer type may be cv-qualified and/or ref-qualified
* e.g. `int foo::*`
# `is_constexpr` lets you check whether a function, member function, or function object is `constexpr`
[heading [simple_fn_obj]]
* Any class/struct with a ['non-templated, non-overloaded] function call operator
* Includes non-generic lambda types
* May be cv-qualified and/or ref-qualified.
* Mutually exclusive with [overloaded_fn_obj]
* e.g. the type of this lambda: `[](int x, int y) { return x + y; }`
# `can_invoke` lets you test `INVOKE`-ability at compile-time using value semantics
[heading [overloaded_fn_obj]]
* Any class/struct with a ['templated or overloaded] function call operator, with the following limitation for those with templated function call operators (which includes generic lambdas):
* If templated , all instantiations must be [@http://stackoverflow.com/questions/35033306/what-does-it-mean-when-one-says-something-is-sfinae-friendly SFINAE-friendly], and must not use [@http://en.cppreference.com/w/cpp/language/dependent_name dependent names], except where the dependent "names" are C++ operators.
* May be cv-qualified and/or ref-qualified
* e.g. the type of this generic lambda: `[](auto x, auto y) { return x + y; }`
# `can_invoke_constexpr` adds a `constexpr`-ness check to `can_invoke`
[warning Generic lambdas or classes with templated function objects that are either not SFINAE-friendly or rely on dependent names for template instantiations are generally incompatible with [libname].]
# `min_arity` can be used to detect default arguments of a function object
[heading [fn_obj]]
* Any type that is either an [overloaded_fn_obj] or a [simple_fn_obj]
[heading [callable]]
* The superset of the following:
* [fn_ptr]
* [fn_ref]
* [fn]
* [abominable]
* [pmf]
* [pmd]
* [fn_obj]
[heading [simple_callable]]
* Includes all [callable] types, [*except for [overloaded_fn_obj]]
[heading [simple_invokable]]
* Includes all [callable] types, [*except for [overloaded_fn_obj], [fn], and [abominable]]
[heading [invokable]]
* Includes all [callable] types, [*except for [fn] and [abominable]]
[heading [constexpr_constructble]]
* Any [@http://en.cppreference.com/w/cpp/concept/LiteralType LiteralType] that is also default-constructible
[endsect]
[section:reasons Why use [libname]?]
[*1.] [libname] offers template aliases such as `remove_function_const` for manipulating function qualifiers, designed to parallel the `<type_traits>` aliases such as `std::remove_const_t`.
[*2.] [libname] is designed to accept cv-qualified and ref-qualified types, which eliminates the need to prepare template argument types with metafunctions such as `std::remove_reference` and `std::decay`. This is especially useful when dealing with perfectly-forwarded parameter types in function templates.
[*3.] [libname] is designed in terms of the [invoke] rules, with one unobtrusive and beneficial deviation: [fn] types and [abominable] types are compatible with all operations that do not specifically require an invocation.
[*4.] [libns]`arg_at<2, Callable>` is both more flexible and more readable than `typename boost::function_traits<Callable>::arg3_type`.
[*5.] [libns]`can_invoke` can be used to test `INVOKE`-ability at compile-time, with value semantics. For the craziest metaprogrammers, [libns]`can_invoke_constexpr` does the same as `can_invoke` for [constexpr_constructible] types, with an added check for `constexpr`-ness (Note: for `can_invoke_constexpr`, argument types must also be [constexpr_constructible])
[*6.] [libns]`is_constexpr` can be used to check whether a [constexpr_constructible] type is a [callable] type that yields a `constexpr` result -- no arguments necessary.
[*7.] [libns]`bind` can be used by library writers to easily accept `std::placeholder` expressions anywhere, without requiring the user to `std::bind` them first. Library writers can then decide to use `std::bind`, `boost::bind`, or whatever implementation suits their needs. Either way, it allows for the creation of more flexible APIs, where a function template taking a "callable type" can be overloaded to also accept placeholder expressions. It's perhaps a small improvement from requiring `std::bind` first, but in API design, even the smallest things count.
[*8.] [libns]`min_arity` can be used to detect the presence of default arguments on a [simple_fn_obj]
[*9.] The [libname] interface mainly consists of template aliases and `constexpr std::integral_constant` functions, which are arguably preferable to `typename foo::type` and `foo::value`. While the `std::integral_constant` functions in [libname] may be a deviation from traditional type trait designs, they facilitate a metaprogramming style that uses value-semantics (a la [@https://boostorg.github.io/hana/ [^Boost.Hana]]). The functions can generally be used with either types or values, which eliminates unnecessary `decltype` usage.
[*10.] [libname] includes optional features for the manipulation and inspection of calling conventions. These features are currently deemed experimental, because they greatly increase the test surface of [libname], are platform-specific, and are not yet fully tested on any platform.
[endsect]
[section:function_sugar Use case: `std::function` sugar]
At the time of this writing, there are 260 [@http://stackoverflow.com/search?q=convert+std%3A%3Abind+to+std%3A%3Afunction search results] on Stack Overflow concerning the conversion from `std::bind` to `std::function`. There are 336 [@http://stackoverflow.com/search?q=convert+lambda+to+std%3A%3Afunction search results] concerning the conversion of lambdas to `std::function`. With this example, we'll kill both birds with the same stone. The `make_function` function defined below will leverage [library_name] to...
At the time of this writing, there are around 260 [@http://stackoverflow.com/search?q=convert+std%3A%3Abind+to+std%3A%3Afunction search results] on Stack Overflow concerning the conversion from `std::bind` to `std::function`. There are roughly 340 [@http://stackoverflow.com/search?q=convert+lambda+to+std%3A%3Afunction search results] concerning the conversion of lambdas to `std::function`. In the example below, we'll kill both birds with the same stone. The `make_function` function will leverage [libname] to...
# Create an `std::function<T>` where T is not explicitly supplied by the user
# Create an `std::function<T>` where T is the deduced "signature" of an `std::placeholders` expression.
@@ -94,21 +198,13 @@ Without real-world context, `make_function` may seem rather silly to those who k
[endsect]
[template ct_open_include[] `#include<`[^[header_include_prefix]]]
[template ct_close_include[]`.hpp>`]
[template include_header[name][ct_open_include][^[name]][ct_close_include][br]]
[section:headers Headers]
The simplest way to use [library_name] is to include the main header file:
The simplest way to use [libname] is to include the main header file:
[include_header callable_traits]
[library_name] interface is also broken down by trait into individual header files. To use only the traits you need, include one or more of the following headers, listed alphabetically:
[libname] interface is also broken down by trait into individual header files. To use only the traits you need, include one or more of the following headers, listed alphabetically:
[include_header [link callable_traits.ref_add_calling_convention add_calling_convention]]
[include_header [link callable_traits.ref_add_function_const add_function_const]]
@@ -153,12 +249,30 @@ The simplest way to use [library_name] is to include the main header file:
[section:ref_add_calling_convention add_calling_convention]
TODO
`add_calling_convention<T, CcTag` will add a calling conventions to a pointer type, where `T` is a [fn_ptr] or [pmf], and `CcTag` is one of the following types:
*[libns]`cdecl_tag`
*[libns]`stdcall_tag`
*[libns]`fastcall_tag`
*[libns]`pascal_tag`
For `add_calling_convention` to actually work, you must:
# Be programming on a supported platform
# Add the calling convention to a pointer type where the platform allows you to do so
# Before including any [libname] headers, you must first define the appropriate macro(s) to enable the desired calling convention(s):
* `CALLABLE_TRAITS_ENABLE_CDECL` for `__cdecl`
* `CALLABLE_TRAITS_ENABLE_STDCALL` for `__stdcall`
* `CALLABLE_TRAITS_ENABLE_FASTCALL` for `__fastcall`
* `CALLABLE_TRAITS_ENABLE_PASCAL` for `pascal`
[warning This feature is currently considered experimental. Your feedback and advice is much appreciated! ]
[heading Example - [^__fastcall] to [^__stdcall]]
[import ../example/changing_calling_conventions.cpp]
[changing_calling_conventions]
[import ../example/experimental_changing_calling_conventions.cpp]
[experimental_changing_calling_conventions]
[heading Example - [^__cdecl]]
[import ../example/calling_convention_cdecl.cpp]
[import ../example/experimental_calling_convention_cdecl.cpp]
[calling_convention_cdecl]
[endsect]
@@ -283,7 +397,7 @@ TODO
[section:ref_has_calling_convention has_calling_convention]
TODO
[heading Example - [^__fastcall] to [^__stdcall]]
[changing_calling_conventions]
[experimental_changing_calling_conventions]
[endsect]
[section:ref_has_varargs has_varargs]
@@ -376,7 +490,7 @@ TODO
[section:ref_remove_calling_convention remove_calling_convention]
TODO
[heading Example - [^__fastcall] to [^__stdcall]]
[changing_calling_conventions]
[experimental_changing_calling_conventions]
[endsect]
[section:ref_remove_function_const remove_function_const]
@@ -427,3 +541,4 @@ TODO
[import ../example/result_of.cpp]
[result_of]
[endsect]

View File

@@ -0,0 +1,10 @@
/*<-
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http ://boost.org/LICENSE_1_0.txt)
->*/
//[ hideous_template
template<typename Return, typename T, typename... Args>
struct foo<Return(T::*)(Args...) const volatile &&> {
//...
};
//]

View File

@@ -27,8 +27,71 @@
<a name="callable_traits.ref_add_calling_convention"></a><a class="link" href="ref_add_calling_convention.html" title="add_calling_convention">add_calling_convention</a>
</h2></div></div></div>
<p>
TODO
<code class="computeroutput"><span class="identifier">add_calling_convention</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">CcTag</span></code>
will add a calling conventions to a type, where <code class="computeroutput"><span class="identifier">T</span></code>
is a <span class="green">FunctionPtr</span> or <span class="green">MemberFunctionPtr</span>,
and <code class="computeroutput"><span class="identifier">CcTag</span></code> is one of the following
types:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
<code class="literal">callable_traits::</code><code class="computeroutput"><span class="identifier">cdecl_tag</span></code>
</li>
<li class="listitem">
<code class="literal">callable_traits::</code><code class="computeroutput"><span class="identifier">stdcall_tag</span></code>
</li>
<li class="listitem">
<code class="literal">callable_traits::</code><code class="computeroutput"><span class="identifier">fastcall_tag</span></code>
</li>
<li class="listitem">
<code class="literal">callable_traits::</code><code class="computeroutput"><span class="identifier">pascal_tag</span></code>
</li>
</ul></div>
<p>
For <code class="computeroutput"><span class="identifier">add_calling_convention</span></code>
to actually work, you must:
</p>
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
Be programming on a supported platform
</li>
<li class="listitem">
Add the calling convention to a pointer type where the platform allows
you to do so
</li>
<li class="listitem">
Before including any <code class="literal">CallableTraits</code> headers, you must
first define the appropriate macro(s) to enable the desired calling convention(s):
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
<code class="computeroutput"><span class="identifier">CALLABLE_TRAITS_ENABLE_CDECL</span></code>
for <code class="computeroutput"><span class="identifier">__cdecl</span></code>
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">CALLABLE_TRAITS_ENABLE_STDCALL</span></code>
for <code class="computeroutput"><span class="identifier">__stdcall</span></code>
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">CALLABLE_TRAITS_ENABLE_FASTCALL</span></code>
for <code class="computeroutput"><span class="identifier">__fastcall</span></code>
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">CALLABLE_TRAITS_ENABLE_PASCAL</span></code>
for <code class="computeroutput"><span class="identifier">pascal</span></code>
</li>
</ul></div>
</li>
</ol></div>
<div class="warning"><table border="0" summary="Warning">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="../../../../../doc/src/images/warning.png"></td>
<th align="left">Warning</th>
</tr>
<tr><td align="left" valign="top"><p>
This feature is currently considered experimental. Your feedback and advice
is much appreciated!
</p></td></tr>
</table></div>
<h4>
<a name="callable_traits.ref_add_calling_convention.h0"></a>
<span class="phrase"><a name="callable_traits.ref_add_calling_convention.example_fastcall_to_stdcall"></a></span><a class="link" href="ref_add_calling_convention.html#callable_traits.ref_add_calling_convention.example_fastcall_to_stdcall">Example
@@ -68,28 +131,9 @@
<span class="phrase"><a name="callable_traits.ref_add_calling_convention.example_cdecl"></a></span><a class="link" href="ref_add_calling_convention.html#callable_traits.ref_add_calling_convention.example_cdecl">Example
- <code class="literal">__cdecl</code></a>
</h4>
<pre class="programlisting"><span class="preprocessor">#define</span> <span class="identifier">CALLABLE_TRAITS_ENABLE_CDECL</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">type_traits</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">has_calling_convention</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">add_calling_convention</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">namespace</span> <span class="identifier">ct</span> <span class="special">=</span> <span class="identifier">callable_traits</span><span class="special">;</span>
<span class="keyword">struct</span> <span class="identifier">foo</span> <span class="special">{};</span>
<span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> <span class="special">{</span>
<span class="comment">//depending on your platform, pmf may alrady have an implicit __cdecl</span>
<span class="keyword">using</span> <span class="identifier">pmf</span> <span class="special">=</span> <span class="keyword">void</span><span class="special">(</span><span class="identifier">foo</span><span class="special">::*)();</span>
<span class="keyword">using</span> <span class="identifier">expect</span> <span class="special">=</span> <span class="keyword">void</span><span class="special">(</span><span class="identifier">__cdecl</span> <span class="identifier">foo</span><span class="special">::*)();</span>
<span class="keyword">using</span> <span class="identifier">test</span> <span class="special">=</span> <span class="identifier">ct</span><span class="special">::</span><span class="identifier">add_calling_convention</span><span class="special">&lt;</span><span class="identifier">pmf</span><span class="special">,</span> <span class="identifier">ct</span><span class="special">::</span><span class="identifier">cdecl_tag</span><span class="special">&gt;;</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">&lt;</span><span class="identifier">test</span><span class="special">,</span> <span class="identifier">expect</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">has_calling_convention</span><span class="special">&lt;</span><span class="identifier">expect</span><span class="special">,</span> <span class="identifier">ct</span><span class="special">::</span><span class="identifier">cdecl_tag</span><span class="special">&gt;(),</span> <span class="string">""</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">has_calling_convention</span><span class="special">&lt;</span><span class="identifier">test</span><span class="special">,</span> <span class="identifier">ct</span><span class="special">::</span><span class="identifier">cdecl_tag</span><span class="special">&gt;(),</span> <span class="string">""</span><span class="special">);</span>
<span class="special">}</span>
</pre>
<p>
[calling_convention_cdecl]
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>

View File

@@ -56,7 +56,6 @@
<span class="keyword">auto</span> <span class="identifier">lamda</span> <span class="special">=</span> <span class="special">[](</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">&amp;,</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*){};</span>
<span class="keyword">using</span> <span class="identifier">lam</span> <span class="special">=</span> <span class="keyword">decltype</span><span class="special">(</span><span class="identifier">lamda</span><span class="special">);</span>
<span class="identifier">test</span><span class="special">&lt;</span><span class="identifier">lam</span><span class="special">&gt;();</span>
<span class="identifier">test</span><span class="special">&lt;</span><span class="identifier">lam</span><span class="special">*&gt;();</span>
<span class="identifier">test</span><span class="special">&lt;</span><span class="identifier">lam</span><span class="special">&amp;&gt;();</span>
<span class="identifier">test</span><span class="special">&lt;</span><span class="identifier">lam</span><span class="special">&amp;&amp;&gt;();</span>
<span class="identifier">test</span><span class="special">&lt;</span><span class="identifier">lam</span> <span class="keyword">const</span> <span class="special">&amp;&gt;();</span>

View File

@@ -53,7 +53,6 @@
<span class="keyword">auto</span> <span class="identifier">lamda</span> <span class="special">=</span> <span class="special">[](</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">float</span><span class="special">&amp;,</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*){};</span>
<span class="keyword">using</span> <span class="identifier">lam</span> <span class="special">=</span> <span class="keyword">decltype</span><span class="special">(</span><span class="identifier">lamda</span><span class="special">);</span>
<span class="identifier">test</span><span class="special">&lt;</span><span class="identifier">lam</span><span class="special">&gt;();</span>
<span class="identifier">test</span><span class="special">&lt;</span><span class="identifier">lam</span><span class="special">*&gt;();</span>
<span class="identifier">test</span><span class="special">&lt;</span><span class="identifier">lam</span><span class="special">&amp;&gt;();</span>
<span class="identifier">test</span><span class="special">&lt;</span><span class="identifier">lam</span><span class="special">&amp;&amp;&gt;();</span>
<span class="identifier">test</span><span class="special">&lt;</span><span class="identifier">lam</span> <span class="keyword">const</span> <span class="special">&amp;&gt;();</span>

View File

@@ -38,9 +38,11 @@
<dl class="toc">
<dt><span class="section"><a href="index.html#callable_traits.introduction">Introduction</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="index.html#callable_traits.introduction.quick_example">Quick Example</a></span></dt>
<dt><span class="section"><a href="index.html#callable_traits.introduction.motivation">Motivation</a></span></dt>
<dt><span class="section"><a href="index.html#callable_traits.introduction.ten_reasons">10 reasons
to use <code class="literal">CallableTraits</code></a></span></dt>
<dt><span class="section"><a href="index.html#callable_traits.introduction.basic_concepts">Concept
Definitions</a></span></dt>
<dt><span class="section"><a href="index.html#callable_traits.introduction.reasons">Why use <code class="literal">CallableTraits</code>?</a></span></dt>
<dt><span class="section"><a href="index.html#callable_traits.introduction.function_sugar">Use case:
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">function</span></code> sugar</a></span></dt>
</dl></dd>
@@ -89,29 +91,101 @@
<a name="callable_traits.introduction"></a><a class="link" href="index.html#callable_traits.introduction" title="Introduction">Introduction</a>
</h2></div></div></div>
<div class="toc"><dl class="toc">
<dt><span class="section"><a href="index.html#callable_traits.introduction.quick_example">Quick Example</a></span></dt>
<dt><span class="section"><a href="index.html#callable_traits.introduction.motivation">Motivation</a></span></dt>
<dt><span class="section"><a href="index.html#callable_traits.introduction.ten_reasons">10 reasons
to use <code class="literal">CallableTraits</code></a></span></dt>
<dt><span class="section"><a href="index.html#callable_traits.introduction.basic_concepts">Concept
Definitions</a></span></dt>
<dt><span class="section"><a href="index.html#callable_traits.introduction.reasons">Why use <code class="literal">CallableTraits</code>?</a></span></dt>
<dt><span class="section"><a href="index.html#callable_traits.introduction.function_sugar">Use case:
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">function</span></code> sugar</a></span></dt>
</dl></div>
<h4>
<a name="callable_traits.introduction.h0"></a>
<span class="phrase"><a name="callable_traits.introduction.quick_example"></a></span><a class="link" href="index.html#callable_traits.introduction.quick_example">Quick
Example</a>
</h4>
<p>
<code class="literal">CallableTraits</code> provides a comprehensive, uniform, and modern
type-level interface for the inspection, decomposition, and synthesis of C++
callable types. This documentation will be most beneficial to readers with
a basic understanding of the syntax and usage of the following C++ features:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
<a href="http://en.cppreference.com/w/cpp/language/partial_specialization" target="_top">template
specializations</a>
</li>
<li class="listitem">
<a href="http://en.cppreference.com/w/cpp/language/sfinae" target="_top">SFINAE</a>
</li>
<li class="listitem">
<a href="http://en.cppreference.com/w/cpp/utility/functional/invoke" target="_top">INVOKE</a>
rules
</li>
<li class="listitem">
function types
</li>
<li class="listitem">
<a href="http://en.cppreference.com/w/cpp/language/pointer#Pointers_to_functions" target="_top">function
pointers</a>
</li>
<li class="listitem">
<a href="http://stackoverflow.com/questions/480248/function-references" target="_top">function
references</a>
</li>
<li class="listitem">
<a href="http://en.cppreference.com/w/cpp/language/pointer#Pointers_to_member_functions" target="_top">pointers
to member functions</a>
</li>
<li class="listitem">
<a href="http://en.cppreference.com/w/cpp/language/pointer#Pointers_to_data_members" target="_top">pointers
to data members</a>
</li>
<li class="listitem">
<a href="http://en.cppreference.com/w/cpp/language/operators#Function_call_operator" target="_top">the
function call operator, <code class="literal">operator()</code></a>
</li>
<li class="listitem">
<a href="https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers" target="_top">universal
references</a> and <a href="http://stackoverflow.com/questions/13725747/concise-explanation-of-reference-collapsing-rules-requested-1-a-a-2" target="_top">reference
collapsing rules</a>
</li>
<li class="listitem">
<a href="http://en.cppreference.com/w/cpp/language/member_functions#const-.2C_volatile-.2C_and_ref-qualified_member_functions" target="_top">cv-qualified
and ref-qualified member functions</a>
</li>
<li class="listitem">
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0172r0.html" target="_top">"abominable"
function types</a>
</li>
<li class="listitem">
<a href="http://en.cppreference.com/w/cpp/language/overloaded_address" target="_top">taking
the address of an overloaded function</a>
</li>
<li class="listitem">
<a href="http://en.cppreference.com/w/c/language/variadic" target="_top">C-style variadics</a>,
a.k.a. <code class="computeroutput"><span class="identifier">varargs</span></code>
</li>
<li class="listitem">
<a href="https://en.wikipedia.org/wiki/X86_calling_conventions" target="_top">calling
conventions</a>
</li>
</ul></div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="callable_traits.introduction.quick_example"></a><a class="link" href="index.html#callable_traits.introduction.quick_example" title="Quick Example">Quick Example</a>
</h3></div></div></div>
<p>
This short program showcases some, but not all, of the features available
in <code class="literal">CallableTraits</code>.
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">type_traits</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">functional</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">tuple</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">callable_traits</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">namespace</span> <span class="identifier">ct</span> <span class="special">=</span> <span class="identifier">callable_traits</span><span class="special">;</span>
<span class="comment">// foo is an example of a function object</span>
<span class="keyword">struct</span> <span class="identifier">foo</span> <span class="special">{</span>
<span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&amp;&amp;,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;,</span> <span class="keyword">void</span><span class="special">*</span> <span class="special">=</span> <span class="keyword">nullptr</span><span class="special">)</span> <span class="keyword">const</span> <span class="special">{}</span>
<span class="special">};</span>
<span class="keyword">namespace</span> <span class="identifier">ct</span> <span class="special">=</span> <span class="identifier">callable_traits</span><span class="special">;</span>
<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">placeholders</span><span class="special">;</span>
<span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> <span class="special">{</span>
<span class="comment">// indexed argument types</span>
@@ -119,173 +193,154 @@
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">&lt;</span><span class="identifier">second_arg</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&amp;&amp;&gt;::</span><span class="identifier">value</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// arg types are packaged into std::tuple, which serves as the default</span>
<span class="comment">// type list in CallableTraits (runtime capabilities are not used).</span>
<span class="comment">// type list in <code class="literal">CallableTraits</code> (runtime capabilities are not used).</span>
<span class="keyword">using</span> <span class="identifier">args</span> <span class="special">=</span> <span class="identifier">ct</span><span class="special">::</span><span class="identifier">args</span><span class="special">&lt;</span><span class="identifier">foo</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">expected_args</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">tuple</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&amp;&amp;,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;,</span> <span class="keyword">void</span><span class="special">*&gt;;</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">&lt;</span><span class="identifier">args</span><span class="special">,</span> <span class="identifier">expected_args</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">//callable_traits::result_of is a bit friendlier than std::result_of</span>
<span class="keyword">using</span> <span class="identifier">return_type</span> <span class="special">=</span> <span class="identifier">ct</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">&lt;</span><span class="identifier">foo</span><span class="special">&gt;;</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">&lt;</span><span class="identifier">return_type</span><span class="special">,</span> <span class="keyword">void</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">//has_void_return is a quicker way to perform the check above</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">has_void_return</span><span class="special">(</span><span class="identifier">foo</span><span class="special">{}),</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// callable_traits::function_type decays a callable type to</span>
<span class="comment">// a plain function type, which is structured in terms of INVOKE</span>
<span class="comment">// <code class="literal">callable_traits::</code>function_type "decays" a callable type to a plain</span>
<span class="comment">// function type, which is structured in terms of INVOKE.</span>
<span class="keyword">using</span> <span class="identifier">function_type</span> <span class="special">=</span> <span class="identifier">ct</span><span class="special">::</span><span class="identifier">function_type</span><span class="special">&lt;</span><span class="identifier">foo</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">expected_function_type</span> <span class="special">=</span> <span class="keyword">void</span><span class="special">(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&amp;&amp;,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;,</span> <span class="keyword">void</span><span class="special">*);</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">&lt;</span><span class="identifier">function_type</span><span class="special">,</span> <span class="identifier">expected_function_type</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// when trait information can be conveyed in an std::integral_constant,</span>
<span class="comment">// callable_traits opts for constexpr functions instead of template aliases.</span>
<span class="comment">// This is done to encourage value semantics, and to simplify usage inside</span>
<span class="comment">// of forwarding functions.</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">arity</span><span class="special">(</span><span class="identifier">foo</span><span class="special">{})</span> <span class="special">==</span> <span class="number">4</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">max_arity</span><span class="special">(</span><span class="identifier">foo</span><span class="special">{})</span> <span class="special">==</span> <span class="number">4</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">min_arity</span><span class="special">(</span><span class="identifier">foo</span><span class="special">{})</span> <span class="special">==</span> <span class="number">3</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// CallableTraits provides constexpr functions so that the user doesn't</span>
<span class="comment">// need to worry about reference collapsing or decltype when dealing with</span>
<span class="comment">// universal references to callables. Still, you don't NEED an instance,</span>
<span class="comment">// because CallableTraits provides non-deduced function templates for</span>
<span class="comment">// all constexpr functions (except for can_invoke/can_invoke_constexpr and bind,</span>
<span class="comment">// which model std::invoke and std::bind, respectively -- more on these below).</span>
<span class="comment">// Here's an example of the non-deduced version of arity, which take an</span>
<span class="comment">// explicit type argument. We'll ignore these non-deduced overloads for the</span>
<span class="comment">// rest of this example.</span>
<span class="comment">// By design, the <code class="literal">CallableTraits</code> interface uses constexpr</span>
<span class="comment">// std::integral_constant functions (whenever sensible).</span>
<span class="comment">// By also defining the appropriate overloads, this gives</span>
<span class="comment">// users the option of using either type arguments or a value</span>
<span class="comment">// arguments, which often eliminates the need for decltype:</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">arity</span><span class="special">&lt;</span><span class="identifier">foo</span><span class="special">&gt;()</span> <span class="special">==</span> <span class="number">4</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">arity</span><span class="special">(</span><span class="identifier">foo</span><span class="special">{})</span> <span class="special">==</span> <span class="number">4</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// C-style variadics detection (ellipses in a signature)</span>
<span class="keyword">static_assert</span><span class="special">(!</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">has_varargs</span><span class="special">(</span><span class="identifier">foo</span><span class="special">{}),</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// Attentive readers might notice that the type of the foo{}</span>
<span class="comment">// expression above is foo&amp;&amp;, rather than foo. Indeed,</span>
<span class="comment">// libname is designed to also allow both ref-qualified</span>
<span class="comment">// and cv-qualified arguments across the board:</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">arity</span><span class="special">&lt;</span><span class="identifier">foo</span><span class="special">&amp;&amp;&gt;()</span> <span class="special">==</span> <span class="number">4</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// Now, if foo had an operator() overload with a &amp;&amp; qualifier, taking</span>
<span class="comment">// a different number of arguments, the above static assert would fail.</span>
<span class="comment">// For consistency, we'll avoid the value-style overloads</span>
<span class="comment">// for the remainder of this example (whenever possible).</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">max_arity</span><span class="special">&lt;</span><span class="identifier">foo</span><span class="special">&gt;()</span> <span class="special">==</span> <span class="number">4</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">min_arity</span><span class="special">&lt;</span><span class="identifier">foo</span><span class="special">&gt;()</span> <span class="special">==</span> <span class="number">3</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// a quick way to check for a void return type</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">has_void_return</span><span class="special">&lt;</span><span class="identifier">foo</span><span class="special">&gt;(),</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// C-style variadics detection (e.g. an ellipses in a signature)</span>
<span class="keyword">static_assert</span><span class="special">(!</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">has_varargs</span><span class="special">&lt;</span><span class="identifier">foo</span><span class="special">&gt;(),</span> <span class="string">""</span><span class="special">);</span>
<span class="keyword">int</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
<span class="comment">// callable_traits::can_invoke allows us to preview whether std::invoke will</span>
<span class="comment">// compile with the given arguments.</span>
<span class="comment">// <code class="literal">callable_traits::</code>can_invoke allows us to preview whether</span>
<span class="comment">// std::invoke would compile with the given arguments.</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">can_invoke</span><span class="special">(</span><span class="identifier">foo</span><span class="special">{},</span> <span class="number">0</span><span class="special">,</span> <span class="number">0</span><span class="special">,</span> <span class="identifier">i</span><span class="special">),</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// no error: std::invoke(foo{}, 0, 0, i);</span>
<span class="comment">// This call returns std::false_type, because it's an illegal call.</span>
<span class="keyword">static_assert</span><span class="special">(!</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">can_invoke</span><span class="special">(</span><span class="identifier">foo</span><span class="special">{},</span> <span class="keyword">nullptr</span><span class="special">),</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// error: std::invoke(foo{}, nullptr);</span>
<span class="comment">// Note that since can_invoke models std::invoke,</span>
<span class="comment">// only a value-style function is defined.</span>
<span class="comment">// For function objects, the following checks are determined by the</span>
<span class="comment">// qualifiers on operator(), rather than the category of the passed value.</span>
<span class="comment">// For member function pointers and abominable function types, the</span>
<span class="comment">// qualifiers on the function type are used.</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">is_const_qualified</span><span class="special">(</span><span class="identifier">foo</span><span class="special">{}),</span> <span class="string">""</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(!</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">is_volatile_qualified</span><span class="special">(</span><span class="identifier">foo</span><span class="special">{}),</span> <span class="string">""</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(!</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">is_reference_qualified</span><span class="special">(</span><span class="identifier">foo</span><span class="special">{}),</span> <span class="string">""</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(!</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">is_lvalue_qualified</span><span class="special">(</span><span class="identifier">foo</span><span class="special">{}),</span> <span class="string">""</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(!</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">is_rvalue_qualified</span><span class="special">(</span><span class="identifier">foo</span><span class="special">{}),</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// If you find yourself in the unfortunate situation of needing</span>
<span class="comment">// to manipulate member function pointer types, CallableTraits</span>
<span class="comment">// has all the tools you need to maintain your sanity.</span>
<span class="comment">// function qualifiers on operator(), rather than the qualifiers on</span>
<span class="comment">// of the type passed. This is done for consistency with member function</span>
<span class="comment">// pointers, where the checks below would look at the function qualifiers</span>
<span class="comment">// (rather than qualifiers on the pointer itself).</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">is_const_qualified</span><span class="special">&lt;</span><span class="identifier">foo</span><span class="special">&gt;(),</span> <span class="string">""</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(!</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">is_volatile_qualified</span><span class="special">&lt;</span><span class="identifier">foo</span><span class="special">&gt;(),</span> <span class="string">""</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(!</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">is_reference_qualified</span><span class="special">&lt;</span><span class="identifier">foo</span><span class="special">&gt;(),</span> <span class="string">""</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(!</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">is_lvalue_qualified</span><span class="special">&lt;</span><span class="identifier">foo</span><span class="special">&gt;(),</span> <span class="string">""</span><span class="special">);</span>
<span class="keyword">static_assert</span><span class="special">(!</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">is_rvalue_qualified</span><span class="special">&lt;</span><span class="identifier">foo</span><span class="special">&gt;(),</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// is_constexpr would return std::true_type if foo's operator() were constexpr.</span>
<span class="keyword">static_assert</span><span class="special">(!</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">is_constexpr</span><span class="special">&lt;</span><span class="identifier">foo</span><span class="special">&gt;(),</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// The same check can be performed using std::integral_constant</span>
<span class="comment">// in conjunction with function addresses:</span>
<span class="keyword">using</span> <span class="identifier">pmf</span> <span class="special">=</span> <span class="keyword">decltype</span><span class="special">(&amp;</span><span class="identifier">foo</span><span class="special">::</span><span class="keyword">operator</span><span class="special">());</span>
<span class="keyword">using</span> <span class="identifier">pmf_constant</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">integral_constant</span><span class="special">&lt;</span><span class="identifier">pmf</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">foo</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()&gt;;</span>
<span class="keyword">static_assert</span><span class="special">(!</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">is_constexpr</span><span class="special">&lt;</span><span class="identifier">pmf_constant</span><span class="special">&gt;(),</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// So that you don't have to scroll back up to see, here's the type of pmf:</span>
<span class="comment">// So that you don't have to scroll to the top to check,</span>
<span class="comment">// here's the type of pmf for reference.</span>
<span class="keyword">using</span> <span class="identifier">with_const</span> <span class="special">=</span> <span class="keyword">void</span> <span class="special">(</span><span class="identifier">foo</span><span class="special">::*)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&amp;&amp;,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;,</span> <span class="keyword">void</span><span class="special">*)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">&lt;</span><span class="identifier">pmf</span><span class="special">,</span> <span class="identifier">with_const</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// Let's remove the const qualifier:</span>
<span class="comment">// If you find yourself in the unfortunate-and-probably-avoidable</span>
<span class="comment">// situation of needing to transform member function pointer</span>
<span class="comment">// types, <code class="literal">CallableTraits</code> has all the tools you need to prolong</span>
<span class="comment">// your sanity.</span>
<span class="comment">// <code class="literal">CallableTraits</code> lets you manipulate qualifiers on PMF types.</span>
<span class="comment">// To remove const:</span>
<span class="keyword">using</span> <span class="identifier">mutable_pmf</span> <span class="special">=</span> <span class="identifier">ct</span><span class="special">::</span><span class="identifier">remove_function_const</span><span class="special">&lt;</span><span class="identifier">pmf</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">without_const</span> <span class="special">=</span> <span class="keyword">void</span> <span class="special">(</span><span class="identifier">foo</span><span class="special">::*)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&amp;&amp;,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;,</span> <span class="keyword">void</span><span class="special">*)</span> <span class="comment">/*no const!*/</span><span class="special">;</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">&lt;</span><span class="identifier">mutable_pmf</span><span class="special">,</span> <span class="identifier">without_const</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// Now let's add an rvalue qualifier (&amp;&amp;):</span>
<span class="comment">// To add an rvalue qualifier:</span>
<span class="keyword">using</span> <span class="identifier">rvalue_pmf</span> <span class="special">=</span> <span class="identifier">ct</span><span class="special">::</span><span class="identifier">add_function_rvalue</span><span class="special">&lt;</span><span class="identifier">pmf</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">with_rvalue</span> <span class="special">=</span> <span class="keyword">void</span> <span class="special">(</span><span class="identifier">foo</span><span class="special">::*)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&amp;&amp;,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;,</span> <span class="keyword">void</span><span class="special">*)</span> <span class="keyword">const</span> <span class="special">&amp;&amp;;</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">&lt;</span><span class="identifier">rvalue_pmf</span><span class="special">,</span> <span class="identifier">with_rvalue</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// You get the picture. CallableTraits lets you add and remove all PMF</span>
<span class="comment">// qualifiers (const, volatile, &amp;, &amp;&amp;, and any combination thereof).</span>
<span class="comment">// These type operations can generally be performed on abominable function</span>
<span class="comment">// types as well.</span>
<span class="comment">// Just like std::add_rvalue_reference, <code class="literal">callable_traits::</code>add_function_rvalue</span>
<span class="comment">// follows C++11 reference collapsing rules. While remove_function_const</span>
<span class="comment">// and add_function_rvalue are somewhat clumsy names, they are the best</span>
<span class="comment">// the best the author could provide while still allowing both terseness</span>
<span class="comment">// and grep-ability against std::remove_const, etc. in &lt;type_traits&gt;.</span>
<span class="comment">// Naturally, <code class="literal">CallableTraits</code> provides similar tools for the other C++</span>
<span class="comment">// function qualifiers. Head to the reference section of this documentation</span>
<span class="comment">// for more examples.</span>
<span class="comment">// is_constexpr would return std::true_type if foo's operator() were constexpr.</span>
<span class="keyword">static_assert</span><span class="special">(!</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">is_constexpr</span><span class="special">(</span><span class="identifier">foo</span><span class="special">{}),</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// To remove a member pointer:</span>
<span class="keyword">using</span> <span class="identifier">fn</span> <span class="special">=</span> <span class="identifier">ct</span><span class="special">::</span><span class="identifier">remove_member_pointer</span><span class="special">&lt;</span><span class="identifier">pmf</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">expected_fn</span> <span class="special">=</span> <span class="keyword">void</span> <span class="special">(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&amp;&amp;,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;,</span> <span class="keyword">void</span><span class="special">*)</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">&lt;</span><span class="identifier">fn</span><span class="special">,</span> <span class="identifier">expected_fn</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// to check constexprness of a function or member function, you must use an</span>
<span class="comment">// std::integral_constant, like this:</span>
<span class="keyword">using</span> <span class="identifier">pmf_constant</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">integral_constant</span><span class="special">&lt;</span><span class="identifier">pmf</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">foo</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()&gt;;</span>
<span class="keyword">static_assert</span><span class="special">(!</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">is_constexpr</span><span class="special">(</span><span class="identifier">pmf_constant</span><span class="special">{}),</span> <span class="string">""</span><span class="special">);</span>
<span class="comment">// We just created an abominable function type - notice the const</span>
<span class="comment">// qualifier! libnsremove_function_const accepts abominable</span>
<span class="comment">// types too (and so does any feature where it is legal to do so):</span>
<span class="keyword">using</span> <span class="identifier">not_abominable</span> <span class="special">=</span> <span class="identifier">ct</span><span class="special">::</span><span class="identifier">remove_function_const</span><span class="special">&lt;</span><span class="identifier">fn</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">expected_fn2</span> <span class="special">=</span> <span class="keyword">void</span> <span class="special">(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&amp;&amp;,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&amp;,</span> <span class="keyword">void</span><span class="special">*);</span>
<span class="keyword">static_assert</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">&lt;</span><span class="identifier">not_abominable</span><span class="special">,</span> <span class="identifier">expected_fn2</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">,</span> <span class="string">""</span><span class="special">);</span>
<span class="special">}</span>
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="callable_traits.introduction.motivation"></a><a class="link" href="index.html#callable_traits.introduction.motivation" title="Motivation">Motivation</a>
</h3></div></div></div>
<p>
The complexity of callable types in C++ is extensive:
Several library solutions exist to manipulate functions or callable types.
However, none of these are comprehensive, and many of them have not aged
well with the advent of modern C++. <code class="literal">CallableTraits</code> fills
the gaps found in existing solutions, and improves upon them wherever possible.
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
function types
</li>
<li class="listitem">
function pointers
</li>
<li class="listitem">
function references
</li>
<li class="listitem">
objects with <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code>
</li>
<li class="listitem">
objects with function pointer conversions
</li>
<li class="listitem">
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0172r0.html" target="_top">"abominable"</a>
function types
</li>
<li class="listitem">
pointers to member data
</li>
<li class="listitem">
pointers to member functions
</li>
<li class="listitem">
qualified overloads of member functions: <code class="computeroutput"><span class="keyword">const</span></code>,
<code class="computeroutput"><span class="keyword">volatile</span></code>, <code class="computeroutput"><span class="special">&amp;</span></code>, <code class="computeroutput"><span class="special">&amp;&amp;</span></code>
</li>
<li class="listitem">
C-style varargs (<code class="computeroutput"><span class="special">...</span></code>)
</li>
<li class="listitem">
calling conventions/attributes (<code class="computeroutput"><span class="identifier">__cdecl</span></code>,
<code class="computeroutput"><span class="identifier">__stdcall</span></code>, <code class="computeroutput"><span class="identifier">__fastcall</span></code>, <code class="computeroutput"><span class="identifier">pascal</span></code>,
etc.)
</li>
<li class="listitem">
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html" target="_top"><code class="literal">noexcept</code></a>
</li>
</ul></div>
<p>
<code class="literal">CallableTraits</code> provides a comprehensive, uniform, and
modern type-level interface for the manipulation and inspection of callable
types in C++. By filling the gaps where existing library solutions fall short,
<code class="literal">CallableTraits</code> aims to provide such an exhaustive interface
for the features listed above that library writers will <span class="bold"><strong>never
again</strong></span> need to specialize templates for callable types. <code class="literal">CallableTraits</code>
eliminates the need for horrific template specializations like these:
Consider for a moment this rather hideous template specialization:
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Ret</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span><span class="special">...</span> <span class="identifier">Args</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">foo</span><span class="special">&lt;</span><span class="identifier">Ret</span><span class="special">(</span><span class="identifier">T</span><span class="special">::*)(</span><span class="identifier">Args</span><span class="special">...,</span> <span class="special">...)</span> <span class="keyword">const</span> <span class="keyword">volatile</span> <span class="special">&amp;&amp;&gt;{</span>
<span class="comment">//...</span>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Return</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span><span class="special">...</span> <span class="identifier">Args</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">foo</span><span class="special">&lt;</span><span class="identifier">Return</span><span class="special">(</span><span class="identifier">T</span><span class="special">::*)(</span><span class="identifier">Args</span><span class="special">...)</span> <span class="keyword">const</span> <span class="keyword">volatile</span> <span class="special">&amp;&amp;&gt;</span> <span class="special">{</span>
<span class="comment">//...</span>
<span class="special">};</span>
</pre>
<p>
Several library solutions exist to manipulate these types, or to abstract
away their complexities. However, these solutions are occasionally inflexible
or lacking in features, especially regarding function objects/lambdas. In
<code class="literal">CallableTraits</code>, function pointers, function references,
function types, abominable function types, member function pointers, member
data pointers, function objects/lambdas, and references/pointers/smart pointers
thereof are generally interchangeable.
Potential use cases for such obscure specializations are vitually nonexistent
in run-of-the-mill C++ application codebases. Even in library code, these
are exceedingly rare. However, there are a handful of specific problems in
C++ that cannot be solved by any other means. While rare, a correct and generic
implementation of these templates is tedious and time consuming. <code class="literal">CallableTraits</code>
premises that these rare cases necessitate a library solution. One goal of
<code class="literal">CallableTraits</code> is to <span class="bold"><strong>completely
and decisively eliminate the need for function signature template specializations</strong></span>.
To the knowledge of the author, <code class="literal">CallableTraits</code> is the
first and only library solution to attempt this.
</p>
<p>
The use cases for <code class="literal">CallableTraits</code> are closely related to
@@ -298,69 +353,310 @@
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top"><p>
The upcoming C++17 ISO standard brings a language change that adds <code class="computeroutput"><span class="keyword">noexcept</span></code> to signatures. Currently, this
is not handled in <code class="literal">CallableTraits</code>, but will be in the
future for platforms that support it.
The upcoming C++17 ISO standard includes a <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html" target="_top">change
to the core language</a> which adds <code class="literal">noexcept</code> to
function signatures. Currently, this is not handled in <code class="literal">CallableTraits</code>.
New features to account for this change are planned in <code class="literal">CallableTraits</code>,
which the author intends to add, with regard for backwards compatibility,
as soon as the language change is implemented in a major compiler.
</p></td></tr>
</table></div>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="callable_traits.introduction.ten_reasons"></a><a class="link" href="index.html#callable_traits.introduction.ten_reasons" title="10 reasons to use CallableTraits">10 reasons
to use <code class="literal">CallableTraits</code></a>
<a name="callable_traits.introduction.basic_concepts"></a><a class="link" href="index.html#callable_traits.introduction.basic_concepts" title="Concept Definitions">Concept
Definitions</a>
</h3></div></div></div>
<div class="orderedlist"><ol class="orderedlist" type="1">
<h5>
<a name="callable_traits.introduction.basic_concepts.h0"></a>
<span class="phrase"><a name="callable_traits.introduction.basic_concepts.fn_ptr"></a></span><a class="link" href="index.html#callable_traits.introduction.basic_concepts.fn_ptr"><span class="green">FunctionPtr</span></a>
</h5>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
<code class="literal">CallableTraits</code>' template aliases and <code class="computeroutput"><span class="keyword">constexpr</span></code> <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">integral_constant</span></code>
functions are preferable to <code class="computeroutput"><span class="keyword">typename</span>
<span class="identifier">foo</span><span class="special">::</span><span class="identifier">type</span></code> and <code class="computeroutput"><span class="identifier">foo</span><span class="special">::</span><span class="identifier">value</span></code>
Any function pointer type
</li>
<li class="listitem">
<code class="literal">CallableTraits</code> offers a familar, consistent interface
for the synthesis and decomposition of callable types
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
e.g. <code class="computeroutput"><span class="identifier">remove_function_const</span></code>
parallels <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_const</span></code>
May be cv-qualified and/or ref-qualified
</li>
<li class="listitem">
e.g. <code class="computeroutput"><span class="keyword">void</span><span class="special">(*)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">)</span></code>
</li>
</ul></div>
<h5>
<a name="callable_traits.introduction.basic_concepts.h1"></a>
<span class="phrase"><a name="callable_traits.introduction.basic_concepts.fn_ref"></a></span><a class="link" href="index.html#callable_traits.introduction.basic_concepts.fn_ref"><span class="green">FunctionReference</span></a>
</h5>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
Any function reference type
</li>
<li class="listitem">
e.g. <code class="computeroutput"><span class="keyword">void</span><span class="special">(&amp;)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">)</span></code>
</li>
</ul></div>
<h5>
<a name="callable_traits.introduction.basic_concepts.h2"></a>
<span class="phrase"><a name="callable_traits.introduction.basic_concepts.fn"></a></span><a class="link" href="index.html#callable_traits.introduction.basic_concepts.fn"><span class="green">Function</span></a>
</h5>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
Any unqualified function type
</li>
<li class="listitem">
e.g. <code class="computeroutput"><span class="keyword">void</span><span class="special">(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">)</span></code>
</li>
</ul></div>
<h5>
<a name="callable_traits.introduction.basic_concepts.h3"></a>
<span class="phrase"><a name="callable_traits.introduction.basic_concepts.abominable"></a></span><a class="link" href="index.html#callable_traits.introduction.basic_concepts.abominable"><span class="green">AbominableFunction</span></a>
</h5>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
Any qualified (a.k.a. <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0172r0.html" target="_top">"abominable"</a>)
function type
</li>
<li class="listitem">
Not technically "callable", but still falls under the <code class="literal">CallableTraits</code>
umbrella
</li>
<li class="listitem">
Mutually exclusive with <span class="green">Function</span>
</li>
<li class="listitem">
e.g. <code class="computeroutput"><span class="keyword">void</span><span class="special">(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">)</span> <span class="keyword">const</span></code>
</li>
</ul></div>
<h5>
<a name="callable_traits.introduction.basic_concepts.h4"></a>
<span class="phrase"><a name="callable_traits.introduction.basic_concepts.pmf"></a></span><a class="link" href="index.html#callable_traits.introduction.basic_concepts.pmf"><span class="green">MemberFunctionPtr</span></a>
</h5>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
Any pointer to member function type
</li>
<li class="listitem">
The pointer type may be cv-qualified and/or ref-qualified
</li>
<li class="listitem">
e.g. <code class="computeroutput"><span class="keyword">void</span> <span class="special">(</span><span class="identifier">foo</span><span class="special">::*)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">)</span></code>
</li>
</ul></div>
<h5>
<a name="callable_traits.introduction.basic_concepts.h5"></a>
<span class="phrase"><a name="callable_traits.introduction.basic_concepts.pmd"></a></span><a class="link" href="index.html#callable_traits.introduction.basic_concepts.pmd"><span class="green">MemberDataPtr</span></a>
</h5>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
Any pointer to data member type
</li>
<li class="listitem">
The pointer type may be cv-qualified and/or ref-qualified
</li>
<li class="listitem">
e.g. <code class="computeroutput"><span class="keyword">int</span> <span class="identifier">foo</span><span class="special">::*</span></code>
</li>
</ul></div>
<h5>
<a name="callable_traits.introduction.basic_concepts.h6"></a>
<span class="phrase"><a name="callable_traits.introduction.basic_concepts.simple_fn_obj"></a></span><a class="link" href="index.html#callable_traits.introduction.basic_concepts.simple_fn_obj"><span class="green">SimpleFunctionObject</span></a>
</h5>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
Any class/struct with a <span class="emphasis"><em>non-templated, non-overloaded</em></span>
function call operator
</li>
<li class="listitem">
Includes non-generic lambda types
</li>
<li class="listitem">
May be cv-qualified and/or ref-qualified.
</li>
<li class="listitem">
Mutually exclusive with <span class="green">OverloadedFunctionObject</span>
</li>
<li class="listitem">
e.g. the type of this lambda: <code class="computeroutput"><span class="special">[](</span><span class="keyword">int</span> <span class="identifier">x</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">x</span> <span class="special">+</span> <span class="identifier">y</span><span class="special">;</span> <span class="special">}</span></code>
</li>
</ul></div>
<h5>
<a name="callable_traits.introduction.basic_concepts.h7"></a>
<span class="phrase"><a name="callable_traits.introduction.basic_concepts.overloaded_fn_obj"></a></span><a class="link" href="index.html#callable_traits.introduction.basic_concepts.overloaded_fn_obj"><span class="green">OverloadedFunctionObject</span></a>
</h5>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
Any class/struct with a <span class="emphasis"><em>templated or overloaded</em></span>
function call operator, with the following limitation for those with
templated function call operators (which includes generic lambdas):
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem">
If templated , all instantiations must be <a href="http://stackoverflow.com/questions/35033306/what-does-it-mean-when-one-says-something-is-sfinae-friendly" target="_top">SFINAE-friendly</a>,
and must not use <a href="http://en.cppreference.com/w/cpp/language/dependent_name" target="_top">dependent
names</a>, except where the dependent "names" are
C++ operators.
</li></ul></div>
</li>
<li class="listitem">
universal references are accepted everywhere, so you don't need to worry
about using <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference</span></code> first
May be cv-qualified and/or ref-qualified
</li>
<li class="listitem">
function object pointers/ pointers are accepted (when <code class="computeroutput"><span class="identifier">INVOKE</span></code>
is not an immediate concern)
e.g. the type of this generic lambda: <code class="computeroutput"><span class="special">[](</span><span class="keyword">auto</span> <span class="identifier">x</span><span class="special">,</span> <span class="keyword">auto</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">x</span> <span class="special">+</span> <span class="identifier">y</span><span class="special">;</span> <span class="special">}</span></code>
</li>
</ul></div>
<div class="warning"><table border="0" summary="Warning">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="../../../../doc/src/images/warning.png"></td>
<th align="left">Warning</th>
</tr>
<tr><td align="left" valign="top"><p>
Generic lambdas or classes with templated function objects that are either
not SFINAE-friendly or rely on dependent names for template instantiations
are generally incompatible with <code class="literal">CallableTraits</code>.
</p></td></tr>
</table></div>
<h5>
<a name="callable_traits.introduction.basic_concepts.h8"></a>
<span class="phrase"><a name="callable_traits.introduction.basic_concepts.fn_obj"></a></span><a class="link" href="index.html#callable_traits.introduction.basic_concepts.fn_obj"><span class="green">FunctionObject</span></a>
</h5>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
Any type that is either an <span class="green">OverloadedFunctionObject</span>
or a <span class="green">SimpleFunctionObject</span>
</li></ul></div>
<h5>
<a name="callable_traits.introduction.basic_concepts.h9"></a>
<span class="phrase"><a name="callable_traits.introduction.basic_concepts.callable"></a></span><a class="link" href="index.html#callable_traits.introduction.basic_concepts.callable"><span class="green">Callable</span></a>
</h5>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
The superset of the following:
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; ">
<li class="listitem">
<code class="computeroutput"><span class="identifier">arg_at</span><span class="special">&lt;</span><span class="number">2</span><span class="special">,</span> <span class="identifier">Callable</span><span class="special">&gt;</span></code> is better than <code class="computeroutput"><span class="keyword">typename</span>
<span class="identifier">function_traits</span><span class="special">&lt;</span><span class="identifier">Callable</span><span class="special">&gt;::</span><span class="identifier">arg2_type</span></code>
</li>
<span class="green">FunctionPtr</span>
</li>
<li class="listitem">
function objects are first-class citizens in <code class="literal">CallableTraits</code>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
e.g. <code class="computeroutput"><span class="identifier">result_of</span></code>
can accept a function object
</li></ul></div>
</li>
<span class="green">FunctionReference</span>
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">is_constexpr</span></code> lets you
check whether a function, member function, or function object is <code class="computeroutput"><span class="keyword">constexpr</span></code>
</li>
<span class="green">Function</span>
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">can_invoke</span></code> lets you test
<code class="computeroutput"><span class="identifier">INVOKE</span></code>-ability at compile-time
using value semantics
</li>
<span class="green">AbominableFunction</span>
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">can_invoke_constexpr</span></code>
adds a <code class="computeroutput"><span class="keyword">constexpr</span></code>-ness check
to <code class="computeroutput"><span class="identifier">can_invoke</span></code>
</li>
<span class="green">MemberFunctionPtr</span>
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">min_arity</span></code> can be used
to detect default arguments of a function object
</li>
</ol></div>
<span class="green">MemberDataPtr</span>
</li>
<li class="listitem">
<span class="green">FunctionObject</span>
</li>
</ul></div>
</li></ul></div>
<h5>
<a name="callable_traits.introduction.basic_concepts.h10"></a>
<span class="phrase"><a name="callable_traits.introduction.basic_concepts.simple_callable"></a></span><a class="link" href="index.html#callable_traits.introduction.basic_concepts.simple_callable"><span class="green">SimpleCallable</span></a>
</h5>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
Includes all <span class="green">Callable</span> types, <span class="bold"><strong>except for <span class="green">OverloadedFunctionObject</span></strong></span>
</li></ul></div>
<h5>
<a name="callable_traits.introduction.basic_concepts.h11"></a>
<span class="phrase"><a name="callable_traits.introduction.basic_concepts.simple_invokable"></a></span><a class="link" href="index.html#callable_traits.introduction.basic_concepts.simple_invokable"><span class="green">SimpleInvokable</span></a>
</h5>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
Includes all <span class="green">Callable</span> types, <span class="bold"><strong>except for <span class="green">OverloadedFunctionObject</span>,
<span class="green">Function</span>, and <span class="green">AbominableFunction</span></strong></span>
</li></ul></div>
<h5>
<a name="callable_traits.introduction.basic_concepts.h12"></a>
<span class="phrase"><a name="callable_traits.introduction.basic_concepts.invokable"></a></span><a class="link" href="index.html#callable_traits.introduction.basic_concepts.invokable"><span class="green">Invokable</span></a>
</h5>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
Includes all <span class="green">Callable</span> types, <span class="bold"><strong>except for <span class="green">Function</span> and <span class="green">AbominableFunction</span></strong></span>
</li></ul></div>
<h5>
<a name="callable_traits.introduction.basic_concepts.h13"></a>
<span class="phrase"><a name="callable_traits.introduction.basic_concepts.constexpr_constructble"></a></span><a class="link" href="index.html#callable_traits.introduction.basic_concepts.constexpr_constructble">[constexpr_constructble]</a>
</h5>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
Any <a href="http://en.cppreference.com/w/cpp/concept/LiteralType" target="_top">LiteralType</a>
that is also default-constructible
</li></ul></div>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="callable_traits.introduction.reasons"></a><a class="link" href="index.html#callable_traits.introduction.reasons" title="Why use CallableTraits?">Why use <code class="literal">CallableTraits</code>?</a>
</h3></div></div></div>
<p>
<span class="bold"><strong>1.</strong></span> <code class="literal">CallableTraits</code> offers
template aliases such as <code class="computeroutput"><span class="identifier">remove_function_const</span></code>
for manipulating function qualifiers, designed to parallel the <code class="computeroutput"><span class="special">&lt;</span><span class="identifier">type_traits</span><span class="special">&gt;</span></code> aliases such as <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_const_t</span></code>.
</p>
<p>
<span class="bold"><strong>2.</strong></span> <code class="literal">CallableTraits</code> is
designed to accept cv-qualified and ref-qualified types, which eliminates
the need to prepare template argument types with metafunctions such as <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference</span></code>
and <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">decay</span></code>. This is especially useful when dealing
with perfectly-forwarded parameter types in function templates.
</p>
<p>
<span class="bold"><strong>3.</strong></span> <code class="literal">CallableTraits</code> is
designed in terms of the <a href="http://en.cppreference.com/w/cpp/utility/functional/invoke" target="_top">INVOKE</a>
rules, with one unobtrusive and beneficial deviation: <span class="green">Function</span>
types and <span class="green">AbominableFunction</span> types are compatible
with all operations that do not specifically require an invocation.
</p>
<p>
<span class="bold"><strong>4.</strong></span> <code class="literal">callable_traits::</code><code class="computeroutput"><span class="identifier">arg_at</span><span class="special">&lt;</span><span class="number">2</span><span class="special">,</span> <span class="identifier">Callable</span><span class="special">&gt;</span></code> is both more flexible and more readable
than <code class="computeroutput"><span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">function_traits</span><span class="special">&lt;</span><span class="identifier">Callable</span><span class="special">&gt;::</span><span class="identifier">arg3_type</span></code>.
</p>
<p>
<span class="bold"><strong>5.</strong></span> <code class="literal">callable_traits::</code><code class="computeroutput"><span class="identifier">can_invoke</span></code> can be used to test <code class="computeroutput"><span class="identifier">INVOKE</span></code>-ability at compile-time, with value
semantics. For the craziest metaprogrammers, <code class="literal">callable_traits::</code><code class="computeroutput"><span class="identifier">can_invoke_constexpr</span></code> does the same as
<code class="computeroutput"><span class="identifier">can_invoke</span></code> for <span class="green">ConstexprDefaultConstructible</span>
types, with an added check for <code class="computeroutput"><span class="keyword">constexpr</span></code>-ness
(Note: for <code class="computeroutput"><span class="identifier">can_invoke_constexpr</span></code>,
argument types must also be <span class="green">ConstexprDefaultConstructible</span>)
</p>
<p>
<span class="bold"><strong>6.</strong></span> <code class="literal">callable_traits::</code><code class="computeroutput"><span class="identifier">is_constexpr</span></code> can be used to check whether
a <span class="green">ConstexprDefaultConstructible</span> type is a
<span class="green">Callable</span> type that yields a <code class="computeroutput"><span class="keyword">constexpr</span></code>
result -- no arguments necessary.
</p>
<p>
<span class="bold"><strong>7.</strong></span> <code class="literal">callable_traits::</code><code class="computeroutput"><span class="identifier">bind</span></code> can be used by library writers to
easily accept <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">placeholder</span></code> expressions anywhere, without
requiring the user to <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">bind</span></code>
them first. Library writers can then decide to use <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">bind</span></code>,
<code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span></code>, or whatever implementation suits
their needs. Either way, it allows for the creation of more flexible APIs,
where a function template taking a "callable type" can be overloaded
to also accept placeholder expressions. It's perhaps a small improvement
from requiring <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">bind</span></code> first, but in API design, even the
smallest things count.
</p>
<p>
<span class="bold"><strong>8.</strong></span> <code class="literal">callable_traits::</code><code class="computeroutput"><span class="identifier">min_arity</span></code> can be used to detect the presence
of default arguments on a <span class="green">SimpleFunctionObject</span>
</p>
<p>
<span class="bold"><strong>9.</strong></span> The <code class="literal">CallableTraits</code>
interface mainly consists of template aliases and <code class="computeroutput"><span class="keyword">constexpr</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">integral_constant</span></code> functions, which are
arguably preferable to <code class="computeroutput"><span class="keyword">typename</span> <span class="identifier">foo</span><span class="special">::</span><span class="identifier">type</span></code>
and <code class="computeroutput"><span class="identifier">foo</span><span class="special">::</span><span class="identifier">value</span></code>. While the <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">integral_constant</span></code>
functions in <code class="literal">CallableTraits</code> may be a deviation from traditional
type trait designs, they facilitate a metaprogramming style that uses value-semantics
(a la <a href="https://boostorg.github.io/hana/" target="_top"><code class="literal">Boost.Hana</code></a>).
The functions can generally be used with either types or values, which eliminates
unnecessary <code class="computeroutput"><span class="keyword">decltype</span></code> usage.
</p>
<p>
<span class="bold"><strong>10.</strong></span> <code class="literal">CallableTraits</code> includes
optional features for the manipulation and inspection of calling conventions.
These features are currently deemed experimental, because they greatly increase
the test surface of <code class="literal">CallableTraits</code>, are platform-specific,
and are not yet fully tested on any platform.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
@@ -368,12 +664,12 @@
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">function</span></code> sugar</a>
</h3></div></div></div>
<p>
At the time of this writing, there are 260 <a href="http://stackoverflow.com/search?q=convert+std%3A%3Abind+to+std%3A%3Afunction" target="_top">search
At the time of this writing, there are around 260 <a href="http://stackoverflow.com/search?q=convert+std%3A%3Abind+to+std%3A%3Afunction" target="_top">search
results</a> on Stack Overflow concerning the conversion from <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">bind</span></code>
to <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">function</span></code>. There are 336 <a href="http://stackoverflow.com/search?q=convert+lambda+to+std%3A%3Afunction" target="_top">search
to <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">function</span></code>. There are roughly 340 <a href="http://stackoverflow.com/search?q=convert+lambda+to+std%3A%3Afunction" target="_top">search
results</a> concerning the conversion of lambdas to <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">function</span></code>.
With this example, we'll kill both birds with the same stone. The <code class="computeroutput"><span class="identifier">make_function</span></code> function defined below will
leverage <code class="literal">CallableTraits</code> to...
In the example below, we'll kill both birds with the same stone. The <code class="computeroutput"><span class="identifier">make_function</span></code> function will leverage <code class="literal">CallableTraits</code>
to...
</p>
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
@@ -400,7 +696,7 @@
<span class="keyword">namespace</span> <span class="identifier">ct</span> <span class="special">=</span> <span class="identifier">callable_traits</span><span class="special">;</span>
<span class="comment">//make_function turns a non-overloaded callable into a type-erased std::function object</span>
<span class="comment">// make_function turns a non-overloaded callable into a type-erased std::function object</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="keyword">inline</span> <span class="keyword">decltype</span><span class="special">(</span><span class="keyword">auto</span><span class="special">)</span> <span class="identifier">make_function</span><span class="special">(</span><span class="identifier">T</span><span class="special">&amp;&amp;</span> <span class="identifier">t</span><span class="special">)</span> <span class="special">{</span>
@@ -412,11 +708,11 @@
<span class="keyword">return</span> <span class="identifier">result_type</span><span class="special">{</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;(</span><span class="identifier">t</span><span class="special">)</span> <span class="special">};</span>
<span class="special">}</span>
<span class="comment">//this make_function overload turns a bind expression into a type-erased std::function object</span>
<span class="comment">// this make_function overload turns a bind expression into a type-erased std::function object</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">First</span><span class="special">,</span> <span class="keyword">typename</span><span class="special">...</span> <span class="identifier">Others</span><span class="special">&gt;</span>
<span class="keyword">inline</span> <span class="keyword">decltype</span><span class="special">(</span><span class="keyword">auto</span><span class="special">)</span> <span class="identifier">make_function</span><span class="special">(</span><span class="identifier">T</span><span class="special">&amp;&amp;</span> <span class="identifier">t</span><span class="special">,</span> <span class="identifier">First</span><span class="special">&amp;&amp;</span> <span class="identifier">first</span><span class="special">,</span> <span class="identifier">Others</span><span class="special">&amp;&amp;...</span> <span class="identifier">others</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">// callable_traits::bind is essentially a compile-time parser of placeholders</span>
<span class="comment">// callable_traits::bind is essentially a compile-time parser of placeholder</span>
<span class="comment">// expressions, for the purpose of retaining more type information than</span>
<span class="comment">// std::bind normally allows - specifically, callable_traits::bind is used to</span>
<span class="comment">// determine the de-facto signature of the std::bind return type, with special</span>

View File

@@ -9,8 +9,11 @@ add_dependencies(check examples)
include_directories(${callable_traits_SOURCE_DIR}/include)
file(GLOB_RECURSE EXAMPLES "*.cpp")
file(GLOB_RECURSE EXCLUDED_EXAMPLES ${EXCLUDED_EXAMPLES})
list(REMOVE_ITEM EXAMPLES "" ${EXCLUDED_EXAMPLES})
if (NOT CALLABLE_TRAITS_BUILD_EXPERIMENTAL)
list(REMOVE_ITEM EXAMPLES "experimental*.cpp")
endif()
foreach(_file IN LISTS EXAMPLES)
callable_traits_target_name_for(_target "${_file}")

View File

@@ -29,7 +29,6 @@ int main() {
auto lamda = [](int, float&, const char*){};
using lam = decltype(lamda);
test<lam>();
test<lam*>();
test<lam&>();
test<lam&&>();
test<lam const &>();

View File

@@ -5,7 +5,7 @@ Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
->*/
//[ calling_convention_cdecl
//[ experimental_calling_convention_cdecl
#define CALLABLE_TRAITS_ENABLE_CDECL

View File

@@ -5,7 +5,7 @@ Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
->*/
//[ changing_calling_conventions
//[ experimental_changing_calling_conventions
#define CALLABLE_TRAITS_ENABLE_STDCALL
#define CALLABLE_TRAITS_ENABLE_FASTCALL

View File

@@ -26,7 +26,6 @@ int main() {
auto lamda = [](int, float&, const char*){};
using lam = decltype(lamda);
test<lam>();
test<lam*>();
test<lam&>();
test<lam&&>();
test<lam const &>();

View File

@@ -5,18 +5,20 @@ Distributed under the Boost Software License, Version 1.0.
->*/
//[ intro
//` This short program showcases some, but not all, of the features available in [libname].
#include <type_traits>
#include <functional>
#include <tuple>
#include <callable_traits/callable_traits.hpp>
namespace ct = callable_traits;
// foo is an example of a function object
struct foo {
void operator()(int, int&&, const int&, void* = nullptr) const {}
};
namespace ct = callable_traits;
using namespace std::placeholders;
int main() {
// indexed argument types
@@ -24,99 +26,121 @@ int main() {
static_assert(std::is_same<second_arg, int&&>::value, "");
// arg types are packaged into std::tuple, which serves as the default
// type list in CallableTraits (runtime capabilities are not used).
// type list in ``[libname]`` (runtime capabilities are not used).
using args = ct::args<foo>;
using expected_args = std::tuple<int, int&&, const int&, void*>;
static_assert(std::is_same<args, expected_args>::value, "");
//callable_traits::result_of is a bit friendlier than std::result_of
using return_type = ct::result_of<foo>;
static_assert(std::is_same<return_type, void>::value, "");
//has_void_return is a quicker way to perform the check above
static_assert(ct::has_void_return(foo{}), "");
// callable_traits::function_type decays a callable type to
// a plain function type, which is structured in terms of INVOKE
// ``[libns]``function_type "decays" a callable type to a plain
// function type, which is structured in terms of INVOKE.
using function_type = ct::function_type<foo>;
using expected_function_type = void(int, int&&, const int&, void*);
static_assert(std::is_same<function_type, expected_function_type>::value, "");
// when trait information can be conveyed in an std::integral_constant,
// callable_traits opts for constexpr functions instead of template aliases.
// This is done to encourage value semantics, and to simplify usage inside
// of forwarding functions.
static_assert(ct::arity(foo{}) == 4, "");
static_assert(ct::max_arity(foo{}) == 4, "");
static_assert(ct::min_arity(foo{}) == 3, "");
// CallableTraits provides constexpr functions so that the user doesn't
// need to worry about reference collapsing or decltype when dealing with
// universal references to callables. Still, you don't NEED an instance,
// because CallableTraits provides non-deduced function templates for
// all constexpr functions (except for can_invoke/can_invoke_constexpr and bind,
// which model std::invoke and std::bind, respectively -- more on these below).
// Here's an example of the non-deduced version of arity, which take an
// explicit type argument. We'll ignore these non-deduced overloads for the
// rest of this example.
// By design, the ``[libname]`` interface uses constexpr
// std::integral_constant functions (whenever sensible).
// By also defining the appropriate overloads, this gives
// users the option of using either type arguments or a value
// arguments, which often eliminates the need for decltype:
static_assert(ct::arity<foo>() == 4, "");
static_assert(ct::arity(foo{}) == 4, "");
// C-style variadics detection (ellipses in a signature)
static_assert(!ct::has_varargs(foo{}), "");
// Attentive readers might notice that the type of the foo{}
// expression above is foo&&, rather than foo. Indeed,
// ``libname`` is designed to also allow both ref-qualified
// and cv-qualified arguments across the board:
static_assert(ct::arity<foo&&>() == 4, "");
// Now, if foo had an operator() overload with a && qualifier, taking
// a different number of arguments, the above static assert would fail.
// For consistency, we'll avoid the value-style overloads
// for the remainder of this example (whenever possible).
static_assert(ct::max_arity<foo>() == 4, "");
static_assert(ct::min_arity<foo>() == 3, "");
// a quick way to check for a void return type
static_assert(ct::has_void_return<foo>(), "");
// C-style variadics detection (e.g. an ellipses in a signature)
static_assert(!ct::has_varargs<foo>(), "");
int i = 0;
// callable_traits::can_invoke allows us to preview whether std::invoke will
// compile with the given arguments.
// ``[libns]``can_invoke allows us to preview whether
// std::invoke would compile with the given arguments.
static_assert(ct::can_invoke(foo{}, 0, 0, i), "");
// no error: std::invoke(foo{}, 0, 0, i);
// This call returns std::false_type, because it's an illegal call.
static_assert(!ct::can_invoke(foo{}, nullptr), "");
// error: std::invoke(foo{}, nullptr);
// Note that since can_invoke models std::invoke,
// only a value-style function is defined.
// For function objects, the following checks are determined by the
// qualifiers on operator(), rather than the category of the passed value.
// For member function pointers and abominable function types, the
// qualifiers on the function type are used.
static_assert(ct::is_const_qualified(foo{}), "");
static_assert(!ct::is_volatile_qualified(foo{}), "");
static_assert(!ct::is_reference_qualified(foo{}), "");
static_assert(!ct::is_lvalue_qualified(foo{}), "");
static_assert(!ct::is_rvalue_qualified(foo{}), "");
// If you find yourself in the unfortunate situation of needing
// to manipulate member function pointer types, CallableTraits
// has all the tools you need to maintain your sanity.
// function qualifiers on operator(), rather than the qualifiers on
// of the type passed. This is done for consistency with member function
// pointers, where the checks below would look at the function qualifiers
// (rather than qualifiers on the pointer itself).
static_assert(ct::is_const_qualified<foo>(), "");
static_assert(!ct::is_volatile_qualified<foo>(), "");
static_assert(!ct::is_reference_qualified<foo>(), "");
static_assert(!ct::is_lvalue_qualified<foo>(), "");
static_assert(!ct::is_rvalue_qualified<foo>(), "");
// is_constexpr would return std::true_type if foo's operator() were constexpr.
static_assert(!ct::is_constexpr<foo>(), "");
// The same check can be performed using std::integral_constant
// in conjunction with function addresses:
using pmf = decltype(&foo::operator());
using pmf_constant = std::integral_constant<pmf, &foo::operator()>;
static_assert(!ct::is_constexpr<pmf_constant>(), "");
// So that you don't have to scroll back up to see, here's the type of pmf:
// So that you don't have to scroll to the top to check,
// here's the type of pmf for reference.
using with_const = void (foo::*)(int, int&&, const int&, void*) const;
static_assert(std::is_same<pmf, with_const>::value, "");
// Let's remove the const qualifier:
// If you find yourself in the unfortunate-and-probably-avoidable
// situation of needing to transform member function pointer
// types, ``[libname]`` has all the tools you need to prolong
// your sanity.
// ``[libname]`` lets you manipulate qualifiers on PMF types.
// To remove const:
using mutable_pmf = ct::remove_function_const<pmf>;
using without_const = void (foo::*)(int, int&&, const int&, void*) /*no const!*/;
static_assert(std::is_same<mutable_pmf, without_const>::value, "");
// Now let's add an rvalue qualifier (&&):
// To add an rvalue qualifier:
using rvalue_pmf = ct::add_function_rvalue<pmf>;
using with_rvalue = void (foo::*)(int, int&&, const int&, void*) const &&;
static_assert(std::is_same<rvalue_pmf, with_rvalue>::value, "");
// You get the picture. CallableTraits lets you add and remove all PMF
// qualifiers (const, volatile, &, &&, and any combination thereof).
// These type operations can generally be performed on abominable function
// types as well.
// Just like std::add_rvalue_reference, ``[libns]``add_function_rvalue
// follows C++11 reference collapsing rules. While remove_function_const
// and add_function_rvalue are somewhat clumsy names, they are the best
// the best the author could provide while still allowing both terseness
// and grep-ability against std::remove_const, etc. in <type_traits>.
// Naturally, ``[libname]`` provides similar tools for the other C++
// function qualifiers. Head to the reference section of this documentation
// for more examples.
// is_constexpr would return std::true_type if foo's operator() were constexpr.
static_assert(!ct::is_constexpr(foo{}), "");
// To remove a member pointer:
using fn = ct::remove_member_pointer<pmf>;
using expected_fn = void (int, int&&, const int&, void*) const;
static_assert(std::is_same<fn, expected_fn>::value, "");
// to check constexprness of a function or member function, you must use an
// std::integral_constant, like this:
using pmf_constant = std::integral_constant<pmf, &foo::operator()>;
static_assert(!ct::is_constexpr(pmf_constant{}), "");
// We just created an abominable function type - notice the const
// qualifier! ``libns``remove_function_const accepts abominable
// types too (and so does any feature where it is legal to do so):
using not_abominable = ct::remove_function_const<fn>;
using expected_fn2 = void (int, int&&, const int&, void*);
static_assert(std::is_same<not_abominable, expected_fn2>::value, "");
}
//]

View File

@@ -13,7 +13,7 @@ namespace example_library {
namespace ct = callable_traits;
//make_function turns a non-overloaded callable into a type-erased std::function object
// make_function turns a non-overloaded callable into a type-erased std::function object
template<typename T>
inline decltype(auto) make_function(T&& t) {
@@ -25,11 +25,11 @@ namespace example_library {
return result_type{ std::forward<T>(t) };
}
//this make_function overload turns a bind expression into a type-erased std::function object
// this make_function overload turns a bind expression into a type-erased std::function object
template<typename T, typename First, typename... Others>
inline decltype(auto) make_function(T&& t, First&& first, Others&&... others) {
// callable_traits::bind is essentially a compile-time parser of placeholders
// callable_traits::bind is essentially a compile-time parser of placeholder
// expressions, for the purpose of retaining more type information than
// std::bind normally allows - specifically, callable_traits::bind is used to
// determine the de-facto signature of the std::bind return type, with special

View File

@@ -14,7 +14,6 @@ Distributed under the Boost Software License, Version 1.0.
#include <callable_traits/detail/set_function_qualifiers.hpp>
#include <callable_traits/detail/qualifiers.hpp>
#include <callable_traits/detail/default_callable_traits.hpp>
#include <callable_traits/detail/utility.hpp>
#include <callable_traits/config.hpp>

View File

@@ -10,9 +10,9 @@ Distributed under the Boost Software License, Version 1.0.
#ifndef CALLABLE_TRAITS_DETAIL_FUNCTION_OBJECT_HPP
#define CALLABLE_TRAITS_DETAIL_FUNCTION_OBJECT_HPP
#include <callable_traits/detail/generalized_class.hpp>
#include <callable_traits/detail/pmf.hpp>
#include <callable_traits/detail/default_callable_traits.hpp>
#include <callable_traits/detail/fwd/function_object_fwd.hpp>
#include <callable_traits/detail/utility.hpp>
#include <tuple>
@@ -21,60 +21,22 @@ namespace callable_traits {
namespace detail {
template<typename T>
struct has_normal_call_operator
{
template<typename N, N Value> struct check { check(std::nullptr_t) {} };
template<typename T, typename Base>
struct function_object : Base {
template<typename U>
static std::int8_t test(check<decltype(&U::operator()), &U::operator()>);
template<typename>
static std::int16_t test(...);
static constexpr bool value = sizeof(test<T>(nullptr)) == sizeof(std::int8_t);
};
struct callable_dummy {
void operator()() {}
};
template<typename T>
using default_normal_callable = typename std::conditional<
has_normal_call_operator<T>::value,
T,
callable_dummy
>::type;
template<typename General>
struct function_object
: std::conditional<
has_normal_call_operator<typename General::type>::value,
pmf<decltype(&default_normal_callable<typename General::type>::operator())>,
default_callable_traits
>::type {
using base = typename std::conditional<
has_normal_call_operator<typename General::type>::value,
pmf<decltype(&default_normal_callable<typename General::type>::operator())>,
default_callable_traits
>::type;
using type = typename General::original_type;
using general_type = typename General::type;
using function_type = typename base::function_object_type;
using invoke_arg_types = typename base::arg_types;
using type = T;
using function_type = typename Base::function_object_type;
using invoke_arg_types = typename Base::arg_types;
static constexpr const bool value =
std::is_class<type>::value && !is_integral_constant<type>::value;
std::is_class<shallow_decay<T>>::value && !is_integral_constant<type>::value;
using traits = function_object;
using class_type = invalid_type;
using invoke_type = invalid_type;
using is_function_object = std::integral_constant<bool,
std::is_class<general_type>::value>;
std::is_class<shallow_decay<T>>::value>;
using is_member_pointer = std::false_type;
using is_member_function_pointer = std::false_type;
@@ -99,8 +61,8 @@ namespace callable_traits {
using remove_function_cv = invalid_type;
};
template<typename T, typename U>
struct function_object <generalized_class<T U::*> >
template<typename T, typename U, typename Base>
struct function_object <T U::*, Base>
: default_callable_traits {};
}
}

View File

@@ -10,14 +10,50 @@ Distributed under the Boost Software License, Version 1.0.
#ifndef CALLABLE_TRAITS_DETAIL_FWD_FUNCTION_OBJECT_FWD_HPP
#define CALLABLE_TRAITS_DETAIL_FWD_FUNCTION_OBJECT_FWD_HPP
#include <callable_traits/detail/utility.hpp>
#include <callable_traits/detail/pmf.hpp>
namespace callable_traits {
namespace detail {
template<typename T>
struct function_object;
struct has_normal_call_operator
{
template<typename N, N Value> struct check { check(std::nullptr_t) {} };
template<typename U>
static std::int8_t test(check<decltype(&U::operator()), &U::operator()>);
template<typename>
static std::int16_t test(...);
static constexpr bool value = sizeof(test<T>(nullptr)) == sizeof(std::int8_t);
};
struct callable_dummy {
void operator()() {}
};
template<typename T>
using default_to_function_object = typename std::conditional<
has_normal_call_operator<T>::value,
T,
callable_dummy
>::type;
template<typename T>
using function_object_base = typename std::conditional<
has_normal_call_operator<T>::value,
pmf<decltype(&default_to_function_object<T>::operator())>,
default_callable_traits
>::type;
//Base is defaulted
template<typename T, typename Base = function_object_base<shallow_decay<T>>>
struct function_object;
}
}
#endif
#endif

View File

@@ -17,62 +17,11 @@ Distributed under the Boost Software License, Version 1.0.
namespace callable_traits {
namespace detail {
template<typename T>
struct can_make_reference {
template<typename U = T>
static U& test(std::nullptr_t);
static dummy test(...);
using type = decltype(can_make_reference::test(nullptr));
static constexpr bool value = !std::is_same<dummy, type>::value;
};
template<typename T>
struct is_class_after_dereference
{
template<typename U,
typename K = typename std::enable_if<can_make_reference<U>::value, U>::type,
typename Dereferenced = decltype(*std::declval<K>()),
typename C = typename std::remove_reference<Dereferenced>::type,
typename std::enable_if<std::is_class<C>::value, int>::type = 0>
static std::int8_t test(int);
template<typename>
static std::int16_t test(...);
static constexpr const bool value =
sizeof(test<T>(0)) == sizeof(std::int8_t);
};
template<typename T>
using can_dereference_to_class = std::integral_constant<bool,
is_class_after_dereference<T>::value
>;
template<typename T>
using cannot_dereference_to_class = std::integral_constant<bool,
!is_class_after_dereference<T>::value
>;
template<typename T, typename = std::true_type>
struct generalized_class;
template<typename T>
struct generalized_class<T, cannot_dereference_to_class<typename std::remove_reference<T>::type>> {
using type = typename std::remove_reference<T>::type;
using original_type = T;
};
template<typename T>
struct generalized_class<T, can_dereference_to_class<typename std::remove_reference<T>::type>> {
using type = typename std::remove_reference<decltype(*std::declval<T>())>::type;
using original_type = T;
};
}
template<typename T>
struct generalized_class {
using type = typename std::remove_reference<T>::type;
using original_type = T;
};
}
#endif

View File

@@ -10,8 +10,6 @@ Distributed under the Boost Software License, Version 1.0.
#ifndef CALLABLE_TRAITS_DETAIL_TRAITS_HPP
#define CALLABLE_TRAITS_DETAIL_TRAITS_HPP
#include <callable_traits/detail/generalized_class.hpp>
#include <callable_traits/detail/utility.hpp>
#include <callable_traits/detail/fwd/pmd_fwd.hpp>
#include <callable_traits/detail/fwd/pmf_fwd.hpp>
@@ -32,14 +30,14 @@ namespace callable_traits {
T
>::type;
template<typename T>
template<typename T, typename Decayed = shallow_decay<T>>
using traits = typename disjunction<
bind_expression_traits<shallow_decay<T>>,
function_object<generalized_class<T>>,
bind_expression_traits<Decayed>,
function_object<T>,
function<decay_if_ptr_or_integral_constant<T>>,
pmf<shallow_decay<T>>,
pmd<shallow_decay<T>>,
function_object<generalized_class<T>>
pmf<Decayed>,
pmd<Decayed>,
function_object<Decayed>
>::traits;
}
}

View File

@@ -1,2 +1,7 @@
TEMPLATE = subdirs
SUBDIRS += main tests_and_examples include doc
SUBDIRS += main \
tests_and_examples \
include \
doc \
project

View File

@@ -1,4 +1,4 @@
TEMPLATE = aux
CONFIG -= qt
OTHER_FILES += ../../doc/*
OTHER_FILES += ../../doc/*

View File

@@ -1,40 +1,144 @@
/*!<-
Copyright (c) 2016 Barrett Adair
/*<-
Copyright Barrett Adair 2016
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
(See accompanying file LICENSE.md or copy at http ://boost.org/LICENSE_1_0.txt)
->*/
//[ calling_convention_cdecl
#define CALLABLE_TRAITS_ENABLE_STDCALL
#define CALLABLE_TRAITS_ENABLE_FASTCALL
//[ intro
//` This short program showcases some, but not all, of the features available in [libname].
#include <type_traits>
#include <callable_traits/has_calling_convention.hpp>
#include <callable_traits/add_calling_convention.hpp>
#include <callable_traits/remove_calling_convention.hpp>
#include <functional>
#include <tuple>
#include <callable_traits/callable_traits.hpp>
namespace ct = callable_traits;
struct foo {};
// foo is an example of a function object
struct foo {
void operator()(int, int&&, const int&, void* = nullptr) const {}
};
int main() {
using f = void(__fastcall *)(int);
// indexed argument types
using second_arg = ct::arg_at<1, foo>;
static_assert(std::is_same<second_arg, int&&>::value, "");
static_assert(ct::has_calling_convention<f, ct::fastcall_tag>(), "");
static_assert(!ct::has_calling_convention<f, ct::stdcall_tag>(), "");
// arg types are packaged into std::tuple, which serves as the default
// type list in ``[libname]`` (runtime capabilities are not used).
using args = ct::args<foo>;
using expected_args = std::tuple<int, int&&, const int&, void*>;
static_assert(std::is_same<args, expected_args>::value, "");
using expect = void(__stdcall *)(int);
// ``[libns]``function_type decays a callable type to
// a plain function type, which is structured in terms of INVOKE
using function_type = ct::function_type<foo>;
using expected_function_type = void(int, int&&, const int&, void*);
static_assert(std::is_same<function_type, expected_function_type>::value, "");
static_assert(ct::has_calling_convention<expect, ct::stdcall_tag>(), "");
static_assert(!ct::has_calling_convention<expect, ct::fastcall_tag>(), "");
// By design, the ``libname`` interface uses constexpr
// std::integral_constant functions (whenever sensible).
// By also defining the appropriate overloads, this gives
// programmers the option of using either type arguments
// or a value arguments:
static_assert(ct::arity<foo>() == 4, "");
static_assert(ct::arity(foo{}) == 4, "");
using g = ct::remove_calling_convention<f>;
using test = ct::add_calling_convention<g, ct::stdcall_tag>;
// Attentive readers might notice that the type of the
// foo{} expression above is foo&&, rather than foo. Indeed,
// ``libname`` is designed to also allow both ref-qualified
// and cv-qualified arguments across the board:
static_assert(ct::has_calling_convention<test, ct::stdcall_tag>(), "");
static_assert(std::is_same<test, expect>::value, "");
static_assert(ct::arity<foo&&>() == 4, "");
// Now, if foo had an operator() overload with a && qualifier,
// taking a different number of arguments, the above static assert
// would fail.
// For consistency, we'll avoid the value-style overloads for
// the remainder of this example whenever possible.
static_assert(ct::max_arity<foo>() == 4, "");
static_assert(ct::min_arity<foo>() == 3, "");
// a quick way to check for a void return type
static_assert(ct::has_void_return<foo>(), "");
// C-style variadics detection (e.g. an ellipses in a signature)
static_assert(!ct::has_varargs<foo>(), "");
int i = 0;
// ``[libns]``can_invoke allows us to preview whether std::invoke
// would compile with the given arguments.
static_assert(ct::can_invoke(foo{}, 0, 0, i), "");
// no error: std::invoke(foo{}, 0, 0, i);
static_assert(!ct::can_invoke(foo{}, nullptr), "");
// error: std::invoke(foo{}, nullptr);
// For function objects, the following checks are determined by the
// value. qualifiers on operator(), rather than the qualifiers on
// of the type passed. This is done for consistency with member
// function pointers, where the checks below would look at the
// function qualifiers (rather than qualifiers on the pointer itself)
static_assert(ct::is_const_qualified<foo>(), "");
static_assert(!ct::is_volatile_qualified<foo>(), "");
static_assert(!ct::is_reference_qualified<foo>(), "");
static_assert(!ct::is_lvalue_qualified<foo>(), "");
static_assert(!ct::is_rvalue_qualified<foo>(), "");
// is_constexpr would return std::true_type if foo's operator() were constexpr.
static_assert(!ct::is_constexpr<foo>(), "");
// The same check can be performed using std::integral_constant
// in conjunction with function addresses:
using pmf = decltype(&foo::operator());
using pmf_constant = std::integral_constant<pmf, &foo::operator()>;
static_assert(!ct::is_constexpr<pmf_constant>(), "");
// So that you don't have to scroll to the top to check,
// here's the type of pmf for reference.
using with_const = void (foo::*)(int, int&&, const int&, void*) const;
static_assert(std::is_same<pmf, with_const>::value, "");
// If you find yourself in the unfortunate-and-probably-avoidable
// situation of needing to transform member function pointer
// types, ``[libname]`` has all the tools you need to prolong
// your sanity.
// ``[libname]`` lets you manipulate qualifiers on PMF types.
// To remove const:
using mutable_pmf = ct::remove_function_const<pmf>;
using without_const = void (foo::*)(int, int&&, const int&, void*) /*no const!*/;
static_assert(std::is_same<mutable_pmf, without_const>::value, "");
// To add an rvalue qualifier:
using rvalue_pmf = ct::add_function_rvalue<pmf>;
using with_rvalue = void (foo::*)(int, int&&, const int&, void*) const &&;
static_assert(std::is_same<rvalue_pmf, with_rvalue>::value, "");
// Just like std::add_rvalue_reference, ``[libns]``add_function_rvalue
// follows C++11 reference collapsing rules. While remove_function_const
// and add_function_rvalue are somewhat clumsy names, they are the best
// the best the author could provide while still allowing both terseness
// and grep-ability against std::remove_const, etc. in <type_traits>.
// Naturally, ``[libname]`` provides similar tools for the other C++
// function qualifiers. Head to the reference section of this documentation
// for more examples.
// To remove a member pointer:
using fn = ct::remove_member_pointer<pmf>;
using expected_fn = void (int, int&&, const int&, void*) const;
static_assert(std::is_same<fn, expected_fn>::value, "");
// We just created an abominable function type - notice the const
// qualifier! ``libns``remove_function_const accepts abominable
// types too:
using not_abominable = ct::remove_function_const<fn>;
using expected_fn2 = void (int, int&&, const int&, void*);
static_assert(std::is_same<not_abominable, expected_fn2>::value, "");
}
//]

View File

@@ -0,0 +1,4 @@
TEMPLATE = aux
CONFIG -= qt
OTHER_FILES += ../../*

View File

@@ -1,8 +1,9 @@
#!/bin/sh
/bin/sh ./internal/build.sh \
../../ \
../../build_clang_libcxx \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_CXX_FLAGS="-stdlib=libc++" \
-DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++ -lc++ -lc++abi"
/bin/sh ./internal/build.sh \
../../ \
../../build_clang_libcxx \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_CXX_FLAGS="-stdlib=libc++" \
-DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++ -lc++ -lc++abi" \
-DCALLABLE_TRAITS_BUILD_EXPERIMENTAL=ON

View File

@@ -1,8 +1,9 @@
#!/bin/sh
/bin/sh ./internal/build.sh \
../../ \
../../build_clang_libstdcxx \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_CXX_FLAGS="-stdlib=libstdc++" \
-DCMAKE_EXE_LINKER_FLAGS="-stdlib=libstdc++ -lstdc++"
/bin/sh ./internal/build.sh \
../../ \
../../build_clang_libstdcxx \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_CXX_FLAGS="-stdlib=libstdc++" \
-DCMAKE_EXE_LINKER_FLAGS="-stdlib=libstdc++ -lstdc++" \
-DCALLABLE_TRAITS_BUILD_EXPERIMENTAL=ON

View File

@@ -1,6 +1,7 @@
#!/bin/sh
/bin/sh ./internal/build.sh \
../../ \
../../build_gcc_libstdcxx \
-DCMAKE_CXX_COMPILER=g++
/bin/sh ./internal/build.sh \
../../ \
../../build_gcc_libstdcxx \
-DCMAKE_CXX_COMPILER=g++ \
-DCALLABLE_TRAITS_BUILD_EXPERIMENTAL=ON

View File

@@ -36,7 +36,7 @@ shift 2
echo $@
# run cmake, expanding the remaining arguments
echo cmake ${project_dir} "$@"
echo cmake ${project_dir} "$@"
cmake ${project_dir} "$@"

View File

@@ -7,10 +7,10 @@ set project_name=%4
::process 1st argument
if "%~1"=="x64" (
set cmake_cmd=cmake .. -TLLVM-vs2014 -G"Visual Studio 14 2015 Win64" -DCMAKE_CXX_FLAGS="-Qunused-arguments"
set cmake_cmd=cmake .. -TLLVM-vs2014 -G"Visual Studio 14 2015 Win64" -DCMAKE_CXX_FLAGS="-Qunused-arguments" -DCALLABLE_TRAITS_BUILD_EXPERIMENTAL
) else (
if "%~1"=="Win32" (
set cmake_cmd=cmake .. -TLLVM-vs2014 -G"Visual Studio 14 2015"
set cmake_cmd=cmake .. -TLLVM-vs2014 -G"Visual Studio 14 2015" -DCALLABLE_TRAITS_BUILD_EXPERIMENTAL=ON
)
)
if not defined cmake_cmd (

View File

@@ -36,7 +36,7 @@ goto main_logic
if not exist ".\Makefile" (
@echo on
cmake -G "MinGW Makefiles" .. -DCMAKE_CXX_COMPILER=g++
cmake -G "MinGW Makefiles" .. -DCMAKE_CXX_COMPILER=g++ -DCALLABLE_TRAITS_BUILD_EXPERIMENTAL=ON
@echo off
) else (
@echo on

View File

@@ -55,11 +55,11 @@ int main() {
{
auto b = ct::bind(
&foo,
ct::bind(&take_vampire, _1),
ct::bind(&take_robot, _1),
ct::bind(&take_dog, _1),
ct::bind(&take_vampire_robot_poodle, _1)
foo,
ct::bind(take_vampire, _1),
ct::bind(take_robot, _1),
ct::bind(take_dog, _1),
ct::bind(take_vampire_robot_poodle, _1)
);
using args = ct::args<decltype(b)>;
@@ -72,11 +72,11 @@ int main() {
{
auto b = ct::bind(
&foo,
ct::bind(&take_vampire_robot_poodle, _1),
ct::bind(&take_vampire, _1),
ct::bind(&take_robot, _1),
ct::bind(&take_dog, _1)
foo,
ct::bind(take_vampire_robot_poodle, _1),
ct::bind(take_vampire, _1),
ct::bind(take_robot, _1),
ct::bind(take_dog, _1)
);
using args = ct::args<decltype(b)>;