Function traits¶
Traits for function type inspection and assembly. For traits specific to member functions, see Member function traits.
This is a complete analog of Boost.CallableTraits (excluding some niche features listed in the Design section) implemented with much less code, so expect reduced compilation times!
Reference¶
Concepts¶
Free functions are typically used in examples for simplicify, but most traits support all the following function concepts, including their const and reference-qualified versions:
#include <actl/functional/traits/FreeFunction.hpp>
-
template<typename T>
concept FreeFunction¶ Concept of a free function, for example,
float(int, int), which is the type of a function like thisfloat divide(int x, int y);
Function reference like
float(&)(int, int)and function pointer likefloat(*)(int, int)also satisfy the concept, because they also support function call syntax.Note
It’s impossible to declare a variable of a function type, it has to be either a reference or a pointer.
#include <actl/functional/traits/MemberFunction.hpp>
-
template<typename T>
concept MemberFunction¶ Concept of a class member function pointer, often called a method.
For example, for the following class
the member function type can be acquired byclass Class { bool member(int) const; };
decltype(&Class::member), which isbool (Class::*)(int) const.Important properties of a member function:
Its type is always a pointer, there’s no corresponding value type.
The first parameter is always the enclosing class.
To support function call syntax it has to be wrapped into
std::mem_fn, otherwise the following call syntax has to be usedauto member = &Class::member; Class instance; (instance.*member)(1);
#include <actl/functional/traits/FunctionObject.hpp>
-
template<typename T>
concept FunctionObject¶ Concept of a function object, that is a type with a non-overloaded
operator(), for exampleNon-template lambdas are also function objects.template<typename T> struct plus { constexpr T operator()(T const& l, T const& r) const { return l + r; } };
#include <actl/functional/traits/Callable.hpp>
-
template<typename Function, typename ...Args>
concept Callable¶ Concept of a type that can be called as a function with the given Args, that is as
fn(args...).Not all the types that are considered to be functions satisfy this concept. In particular, member functions are called using special syntax
(instance.*member)(args...);
C++ provides
std::invokeas a unified way to call all the functions. However, we highly recommend not to use it and instead wrap member functions intostd::mem_fnwhen they need to be called in a unified way. That’s becausestd::invokeadds 1 or 2 nested function calls for every function (not just member functions that are rarely called this way), which in debug mode require more manual actions to step into, and overall decrease performance if not inlined. This problem isn’t as critical because it’s specific to debug builds. But there’s a simplestd::mem_fnsolution to avoid it completely.Note
Some libraries support pointers to data members similarly to pointers to member functions. Data members are obviously not functions, but they are indeed related and this makes sense, for example, for std::mem_fn. However, the result of applying a pointer to data member to a class object inherits the qualifiers of this object. So, it defines not a single function, but an overload set, which is not supported by the library as of now.
Traits¶
#include <actl/functional/traits/function_traits.hpp>
-
template<typename T>
struct function_traits¶ If
Tis a function, then the following members are specified:category as ac::function_category;
return_type;
parameters_type as ac::type_array;
accepts_variadic_arguments as a
bool;is_noexcept as a
bool.
Return type¶
#include <actl/functional/traits/return.hpp>
-
template<typename Function>
using ac::return_t = typename function_traits<Function>::return_type¶
-
template<typename T, typename ReturnType>
using ac::with_return_type_t = typename with_return_type<T, ReturnType>::type¶ Resulting type is different for different input types T:
If T is a function, then it’s a function with the given return type, but otherwise identical to T.
If T is an ac::type_array template instantiaion, then it’s a free function with the given return type and T as its parameters list.
Trait name
Example 1
Example 2
Input type
Fnfloat(int, int) noexceptvoid(const char*, ...)return_tfloatvoidreturns_void_vfalsetruewith_return_type_t<Fn, int>int(int, int) noexceptint(const char*, ...)Parameters¶
#include <actl/functional/traits/parameters.hpp>
-
template<typename Function>
using ac::parameters_t = typename function_traits<Function>::parameters_type¶ Parameter types of a function as ac::type_array.
Note
Arguments name is sometimes incorrectly used instead of parameters. Arguments are the values passed to the function when called, so they are not a property of the function itself.
-
template<typename Function>
size_t ac::arity_v = parameters_t<Function>::length¶ Arity of the function, that is its parameter count excluding the variadic arguments.
-
template<typename Function, size_t Index>
using ac::parameter_at_t = at_t<parameters_t<Function>, Index>¶
-
template<typename Function>
using ac::unique_parameters_t = typename unique_parameters<Function>::type¶ Member functions with either empty or & qualifier both take the class parameter by reference. To disambiguate these cases, unique parameter types contain class parameter with the same qualifiers as the member function, without the implicitly added reference.
Trait name
Example 1
Example 2
Input type
Fnfloat(int, int) noexceptvoid(const char*, ...)parameters_tac::type_array<int, int>ac::type_array<const char*>arity_v21parameter_at_t<Fn, 0>intconst char*Variadic arguments¶
#include <actl/functional/traits/variadic_arguments.hpp>
-
template<typename Function>
bool ac::accepts_variadic_arguments_v = function_traits<Function>::accepts_variadic_arguments¶ Checks if the function accepts variadic arguments, see https://en.cppreference.com/w/cpp/language/variadic_arguments.html
-
template<typename Function>
using ac::add_variadic_arguments_t = typename add_variadic_arguments<Function>::type¶
-
template<typename Function>
using ac::remove_variadic_arguments_t = typename remove_variadic_arguments<Function>::type¶
Trait name
Example 1
Example 2
Input type
float(int, int) noexceptvoid(const char*, ...)accepts_variadic_arguments_vfalsetrueadd_variadic_arguments_tfloat(int, int, ...) noexceptvoid(const char*, ...)remove_variadic_arguments_tfloat(int, int) noexceptvoid(const char*)noexcept¶#include <actl/functional/traits/noexcept.hpp>
-
template<typename Function>
bool ac::is_noexcept_v = function_traits<Function>::is_noexcept¶ Checks if the function is noexcept, see https://en.cppreference.com/w/cpp/language/noexcept_spec.html
Trait name
Example 1
Example 2
Input type
float(int, int) noexceptvoid(const char*, ...)is_noexcept_vtruefalseadd_noexcept_tfloat(int, int) noexceptvoid(const char*, ...) noexceptremove_noexcept_tfloat(int, int)void(const char*, ...)Function type assembly¶
#include <actl/functional/traits/assemble_function.hpp>
-
template<function_category Category, typename Return, typename ParametersList, bool AcceptsVArgs, bool IsNoexcept>
using ac::assemble_function_t = typename assemble_function<Category, Return, ParametersList, AcceptsVArgs, IsNoexcept>::type¶ Assembles a function type with the given properties.
-
template<typename Function>
using ac::as_free_function_t = typename as_free_function<Function>::type¶ Free function with the same parameters and return type as Function.
See tests at tests/functional/traits/
Design¶
The following reference was used at first, but it was heavily expanded.
Qualified free functions¶
Boost.CallableTraits supports qualified free function types like
Return(Args...) const volatile &
These types indeed exist in C++, but declaring a function like
void f() const {}results in a compilation error. This is confirmed by cppreference:cv - const/volatile qualification, only allowed in non-static member function declarations
ref - (since C++11) ref-qualification, only allowed in non-static member function declarations
It’s not clear why such types exist if they cannot be used in a declaration. For this reason, we don’t support them.
transaction_safe¶transaction_safe keyword from Transactional Memory TS isn’t supported, because it’s still experimental for a long time without notable progress.
We prefer not to add extra complexity to the library to support non-standard extensions.
-
template<typename T>
-
template<typename Function, typename ...Args>
-
template<typename T>