mirror of
https://github.com/boostorg/callable_traits.git
synced 2026-02-12 12:02:24 +00:00
Merge remote-tracking branch 'refs/remotes/origin/master' into gh-pages
This commit is contained in:
@@ -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]
|
||||
|
||||
|
||||
10
doc/hideous_template.snippet.cpp
Normal file
10
doc/hideous_template.snippet.cpp
Normal 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 &&> {
|
||||
//...
|
||||
};
|
||||
//]
|
||||
@@ -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"><</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"><</span><span class="identifier">type_traits</span><span class="special">></span>
|
||||
<span class="preprocessor">#include</span> <span class="special"><</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">></span>
|
||||
<span class="preprocessor">#include</span> <span class="special"><</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">></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"><</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">>;</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"><</span><span class="identifier">test</span><span class="special">,</span> <span class="identifier">expect</span><span class="special">>::</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"><</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">>(),</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"><</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">>(),</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>
|
||||
|
||||
@@ -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">&,</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"><</span><span class="identifier">lam</span><span class="special">>();</span>
|
||||
<span class="identifier">test</span><span class="special"><</span><span class="identifier">lam</span><span class="special">*>();</span>
|
||||
<span class="identifier">test</span><span class="special"><</span><span class="identifier">lam</span><span class="special">&>();</span>
|
||||
<span class="identifier">test</span><span class="special"><</span><span class="identifier">lam</span><span class="special">&&>();</span>
|
||||
<span class="identifier">test</span><span class="special"><</span><span class="identifier">lam</span> <span class="keyword">const</span> <span class="special">&>();</span>
|
||||
|
||||
@@ -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">&,</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"><</span><span class="identifier">lam</span><span class="special">>();</span>
|
||||
<span class="identifier">test</span><span class="special"><</span><span class="identifier">lam</span><span class="special">*>();</span>
|
||||
<span class="identifier">test</span><span class="special"><</span><span class="identifier">lam</span><span class="special">&>();</span>
|
||||
<span class="identifier">test</span><span class="special"><</span><span class="identifier">lam</span><span class="special">&&>();</span>
|
||||
<span class="identifier">test</span><span class="special"><</span><span class="identifier">lam</span> <span class="keyword">const</span> <span class="special">&>();</span>
|
||||
|
||||
@@ -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"><</span><span class="identifier">type_traits</span><span class="special">></span>
|
||||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">functional</span><span class="special">></span>
|
||||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">tuple</span><span class="special">></span>
|
||||
<span class="preprocessor">#include</span> <span class="special"><</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">></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">&&,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&,</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"><</span><span class="identifier">second_arg</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&&>::</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"><</span><span class="identifier">foo</span><span class="special">>;</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"><</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&&,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&,</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"><</span><span class="identifier">args</span><span class="special">,</span> <span class="identifier">expected_args</span><span class="special">>::</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"><</span><span class="identifier">foo</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"><</span><span class="identifier">return_type</span><span class="special">,</span> <span class="keyword">void</span><span class="special">>::</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"><</span><span class="identifier">foo</span><span class="special">>;</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">&&,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&,</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"><</span><span class="identifier">function_type</span><span class="special">,</span> <span class="identifier">expected_function_type</span><span class="special">>::</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"><</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">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&&, 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"><</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">// Now, if foo had an operator() overload with a && 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"><</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">// 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"><</span><span class="identifier">foo</span><span class="special">>(),</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"><</span><span class="identifier">foo</span><span class="special">>(),</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"><</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">// 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">// 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">(&</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"><</span><span class="identifier">pmf</span><span class="special">,</span> <span class="special">&</span><span class="identifier">foo</span><span class="special">::</span><span class="keyword">operator</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_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">// 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">&&,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&,</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"><</span><span class="identifier">pmf</span><span class="special">,</span> <span class="identifier">with_const</span><span class="special">>::</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"><</span><span class="identifier">pmf</span><span class="special">>;</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">&&,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&,</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"><</span><span class="identifier">mutable_pmf</span><span class="special">,</span> <span class="identifier">without_const</span><span class="special">>::</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 (&&):</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"><</span><span class="identifier">pmf</span><span class="special">>;</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">&&,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&,</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"><</span><span class="identifier">rvalue_pmf</span><span class="special">,</span> <span class="identifier">with_rvalue</span><span class="special">>::</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, &, &&, 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 <type_traits>.</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"><</span><span class="identifier">pmf</span><span class="special">>;</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">&&,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&,</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"><</span><span class="identifier">fn</span><span class="special">,</span> <span class="identifier">expected_fn</span><span class="special">>::</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"><</span><span class="identifier">pmf</span><span class="special">,</span> <span class="special">&</span><span class="identifier">foo</span><span class="special">::</span><span class="keyword">operator</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_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"><</span><span class="identifier">fn</span><span class="special">>;</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">&&,</span> <span class="keyword">const</span> <span class="keyword">int</span><span class="special">&,</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"><</span><span class="identifier">not_abominable</span><span class="special">,</span> <span class="identifier">expected_fn2</span><span class="special">>::</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">&</span></code>, <code class="computeroutput"><span class="special">&&</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"><</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">></span>
|
||||
<span class="keyword">struct</span> <span class="identifier">foo</span><span class="special"><</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">&&>{</span>
|
||||
<span class="comment">//...</span>
|
||||
<pre class="programlisting"><span class="keyword">template</span><span class="special"><</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">></span>
|
||||
<span class="keyword">struct</span> <span class="identifier">foo</span><span class="special"><</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">&&></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">(&)(</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"><</span><span class="number">2</span><span class="special">,</span> <span class="identifier">Callable</span><span class="special">></span></code> is better than <code class="computeroutput"><span class="keyword">typename</span>
|
||||
<span class="identifier">function_traits</span><span class="special"><</span><span class="identifier">Callable</span><span class="special">>::</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"><</span><span class="identifier">type_traits</span><span class="special">></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"><</span><span class="number">2</span><span class="special">,</span> <span class="identifier">Callable</span><span class="special">></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"><</span><span class="identifier">Callable</span><span class="special">>::</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"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></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">&&</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"><</span><span class="identifier">T</span><span class="special">>(</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"><</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">></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">&&</span> <span class="identifier">t</span><span class="special">,</span> <span class="identifier">First</span><span class="special">&&</span> <span class="identifier">first</span><span class="special">,</span> <span class="identifier">Others</span><span class="special">&&...</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>
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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 &>();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 &>();
|
||||
|
||||
@@ -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, "");
|
||||
}
|
||||
//]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
|
||||
@@ -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 {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS += main tests_and_examples include doc
|
||||
|
||||
SUBDIRS += main \
|
||||
tests_and_examples \
|
||||
include \
|
||||
doc \
|
||||
project
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
TEMPLATE = aux
|
||||
CONFIG -= qt
|
||||
|
||||
OTHER_FILES += ../../doc/*
|
||||
OTHER_FILES += ../../doc/*
|
||||
|
||||
@@ -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, "");
|
||||
}
|
||||
//]
|
||||
|
||||
4
qtcreator/project/project.pro
Normal file
4
qtcreator/project/project.pro
Normal file
@@ -0,0 +1,4 @@
|
||||
TEMPLATE = aux
|
||||
CONFIG -= qt
|
||||
|
||||
OTHER_FILES += ../../*
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -36,7 +36,7 @@ shift 2
|
||||
echo $@
|
||||
|
||||
# run cmake, expanding the remaining arguments
|
||||
echo cmake ${project_dir} "$@"
|
||||
echo cmake ${project_dir} "$@"
|
||||
cmake ${project_dir} "$@"
|
||||
|
||||
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)>;
|
||||
|
||||
Reference in New Issue
Block a user