#include <tuple>
#include <type_traits>
/// @class FunctionTraits is a common traits class for various types:
/// ordinary functions, function objects and lambdas
template <typename>
struct FunctionTraits;
template <typename ReturnT, typename...ParamT>
struct FunctionTraits<ReturnT(ParamT...)>
{
static constexpr size_t Arity = sizeof...(ParamT);
using Signature = ReturnT(ParamT...);
using ReturnType = ReturnT;
using ParameterTypes = std::tuple<ParamT...>;
};
template <typename ReturnT, typename...ParamT>
struct FunctionTraits<ReturnT(*)(ParamT...)> : FunctionTraits<ReturnT(ParamT...)> {};
template <typename T, typename ReturnT, typename...ParamT>
struct FunctionTraits<ReturnT(T::*)(ParamT...)> : FunctionTraits<ReturnT(ParamT...)> {};
template <typename T, typename ReturnT, typename...ParamT>
struct FunctionTraits<ReturnT(T::*)(ParamT...) const> : FunctionTraits<ReturnT(ParamT...)> {};
template <typename T>
struct FunctionTraits : FunctionTraits<decltype(&std::decay<T>::type::operator())> {};
///@brief Get function arity
template <typename T>
constexpr size_t FunctionArity = FunctionTraits<T>::Arity;
///@brief Get function signature
template <typename T>
using FunctionSignature = typename FunctionTraits<T>::Signature;
///@brief Get function return type
template <typename T>
using FunctionReturnType = typename FunctionTraits<T>::ReturnType;
///@brief Get function parameter type by its order index
template <typename T, size_t I>
using FunctionParameterType = typename std::tuple_element<I, typename FunctionTraits<T>::ParameterTypes>::type;
int main()
{
auto lambda = [](int, double, const std::string&) { return 42; };
using LambdaType = decltype(lambda);
static_assert(FunctionArity<LambdaType> == 3, "");
static_assert(std::is_same<int, FunctionParameterType<LambdaType, 0>>::value, "");
static_assert(std::is_same<double, FunctionParameterType<LambdaType, 1>>::value, "");
static_assert(std::is_same<const std::string&, FunctionParameterType<LambdaType, 2>>::value, "");
static_assert(std::is_same<int, FunctionReturnType<LambdaType>>::value, "");
}
I2luY2x1ZGUgPHR1cGxlPgojaW5jbHVkZSA8dHlwZV90cmFpdHM+CgovLy8gQGNsYXNzIEZ1bmN0aW9uVHJhaXRzIGlzIGEgY29tbW9uIHRyYWl0cyBjbGFzcyBmb3IgdmFyaW91cyB0eXBlczoKLy8vIG9yZGluYXJ5IGZ1bmN0aW9ucywgZnVuY3Rpb24gb2JqZWN0cyBhbmQgbGFtYmRhcwp0ZW1wbGF0ZSA8dHlwZW5hbWU+CnN0cnVjdCBGdW5jdGlvblRyYWl0czsKCnRlbXBsYXRlIDx0eXBlbmFtZSBSZXR1cm5ULCB0eXBlbmFtZS4uLlBhcmFtVD4Kc3RydWN0IEZ1bmN0aW9uVHJhaXRzPFJldHVyblQoUGFyYW1ULi4uKT4KewogICBzdGF0aWMgY29uc3RleHByIHNpemVfdCBBcml0eSA9IHNpemVvZi4uLihQYXJhbVQpOwogICB1c2luZyBTaWduYXR1cmUgPSBSZXR1cm5UKFBhcmFtVC4uLik7CiAgIHVzaW5nIFJldHVyblR5cGUgPSBSZXR1cm5UOwogICB1c2luZyBQYXJhbWV0ZXJUeXBlcyA9IHN0ZDo6dHVwbGU8UGFyYW1ULi4uPjsKfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBSZXR1cm5ULCB0eXBlbmFtZS4uLlBhcmFtVD4Kc3RydWN0IEZ1bmN0aW9uVHJhaXRzPFJldHVyblQoKikoUGFyYW1ULi4uKT4gOiBGdW5jdGlvblRyYWl0czxSZXR1cm5UKFBhcmFtVC4uLik+IHt9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIFQsIHR5cGVuYW1lIFJldHVyblQsIHR5cGVuYW1lLi4uUGFyYW1UPgpzdHJ1Y3QgRnVuY3Rpb25UcmFpdHM8UmV0dXJuVChUOjoqKShQYXJhbVQuLi4pPiA6IEZ1bmN0aW9uVHJhaXRzPFJldHVyblQoUGFyYW1ULi4uKT4ge307Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwgdHlwZW5hbWUgUmV0dXJuVCwgdHlwZW5hbWUuLi5QYXJhbVQ+CnN0cnVjdCBGdW5jdGlvblRyYWl0czxSZXR1cm5UKFQ6OiopKFBhcmFtVC4uLikgY29uc3Q+IDogRnVuY3Rpb25UcmFpdHM8UmV0dXJuVChQYXJhbVQuLi4pPiB7fTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBUPgpzdHJ1Y3QgRnVuY3Rpb25UcmFpdHMgOiBGdW5jdGlvblRyYWl0czxkZWNsdHlwZSgmc3RkOjpkZWNheTxUPjo6dHlwZTo6b3BlcmF0b3IoKSk+IHt9OwoKLy8vQGJyaWVmIEdldCBmdW5jdGlvbiBhcml0eQp0ZW1wbGF0ZSA8dHlwZW5hbWUgVD4KY29uc3RleHByIHNpemVfdCBGdW5jdGlvbkFyaXR5ID0gRnVuY3Rpb25UcmFpdHM8VD46OkFyaXR5OwoKLy8vQGJyaWVmIEdldCBmdW5jdGlvbiBzaWduYXR1cmUKdGVtcGxhdGUgPHR5cGVuYW1lIFQ+CnVzaW5nIEZ1bmN0aW9uU2lnbmF0dXJlID0gdHlwZW5hbWUgRnVuY3Rpb25UcmFpdHM8VD46OlNpZ25hdHVyZTsKCi8vL0BicmllZiBHZXQgZnVuY3Rpb24gcmV0dXJuIHR5cGUKdGVtcGxhdGUgPHR5cGVuYW1lIFQ+CnVzaW5nIEZ1bmN0aW9uUmV0dXJuVHlwZSA9IHR5cGVuYW1lIEZ1bmN0aW9uVHJhaXRzPFQ+OjpSZXR1cm5UeXBlOwoKLy8vQGJyaWVmIEdldCBmdW5jdGlvbiBwYXJhbWV0ZXIgdHlwZSBieSBpdHMgb3JkZXIgaW5kZXgKdGVtcGxhdGUgPHR5cGVuYW1lIFQsIHNpemVfdCBJPgp1c2luZyBGdW5jdGlvblBhcmFtZXRlclR5cGUgPSB0eXBlbmFtZSBzdGQ6OnR1cGxlX2VsZW1lbnQ8SSwgdHlwZW5hbWUgRnVuY3Rpb25UcmFpdHM8VD46OlBhcmFtZXRlclR5cGVzPjo6dHlwZTsKCgppbnQgbWFpbigpCnsKICAgYXV0byBsYW1iZGEgPSBbXShpbnQsIGRvdWJsZSwgY29uc3Qgc3RkOjpzdHJpbmcmKSB7IHJldHVybiA0MjsgfTsKICAgdXNpbmcgTGFtYmRhVHlwZSA9IGRlY2x0eXBlKGxhbWJkYSk7CgogICBzdGF0aWNfYXNzZXJ0KEZ1bmN0aW9uQXJpdHk8TGFtYmRhVHlwZT4gPT0gMywgIiIpOwogICBzdGF0aWNfYXNzZXJ0KHN0ZDo6aXNfc2FtZTxpbnQsIEZ1bmN0aW9uUGFyYW1ldGVyVHlwZTxMYW1iZGFUeXBlLCAwPj46OnZhbHVlLCAiIik7CiAgIHN0YXRpY19hc3NlcnQoc3RkOjppc19zYW1lPGRvdWJsZSwgRnVuY3Rpb25QYXJhbWV0ZXJUeXBlPExhbWJkYVR5cGUsIDE+Pjo6dmFsdWUsICIiKTsKICAgc3RhdGljX2Fzc2VydChzdGQ6OmlzX3NhbWU8Y29uc3Qgc3RkOjpzdHJpbmcmLCBGdW5jdGlvblBhcmFtZXRlclR5cGU8TGFtYmRhVHlwZSwgMj4+Ojp2YWx1ZSwgIiIpOwogICBzdGF0aWNfYXNzZXJ0KHN0ZDo6aXNfc2FtZTxpbnQsIEZ1bmN0aW9uUmV0dXJuVHlwZTxMYW1iZGFUeXBlPj46OnZhbHVlLCAiIik7Cn0K