2016-03-25 15:59:49 -05:00
2016-03-14 07:51:31 -05:00
2016-03-25 15:59:49 -05:00
2016-03-25 15:58:06 -05:00
2016-03-14 07:51:31 -05:00
2016-03-24 03:31:25 -05:00

CallableTraits

Build Status

Gitter

This is currently an unfinished project. Lack of documentation, gaps in cross-platform compatibility, and spotty code quality are the most glaring issues right now, but progress is being made on all fronts.

CallableTraits intends to provide a uniform and comprehensive interface for type-level manipulation of all callable types in C++.

Overview


#include <type_traits>
#include <functional>
#include <tuple>
#include <callable_traits/callable_traits.hpp>

// This example uses a function object. All features shown in this example
// can be used for other callable types, including (but not limited to) function
// pointers and member function pointers. Ambiguous callables (e.g. function
// objects with templated/overloaded operator()) are not discussed in this example.

struct foo {
    void operator()(int, char, float, void* = nullptr) const {}
};

namespace ct = callable_traits;
using namespace std::placeholders;

int main() {

    // indexed argument types
    using second_arg = ct::arg_at<1, foo>;
    static_assert(std::is_same<second_arg, char>{}, "");

    // arguments in a tuple
    using args = ct::args<foo>;
    using expected_args = std::tuple<int, char, float, void*>;
    static_assert(std::is_same<args, expected_args>{}, "");

    //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>{}, "");

    // callable_traits::signature yields a plain function type
    using signature = ct::signature<foo>;
    using expected_signature = void(int, char, float, void*);
    static_assert(std::is_same<signature, expected_signature>{}, "");

    // when trait information can be conveyed in an integral_constant,
    // callable_traits uses functions instead of template aliases.
    // The line below could use ct::arity<foo>() instead. This applies
    // to all function-style type traits. Note: min_arity and max_arity
    // only differ from arity when the argument is a function object.
    static_assert(ct::arity(foo{}) == 4, "");
    static_assert(ct::max_arity(foo{}) == 4, "");
    static_assert(ct::min_arity(foo{}) == 3, "");

    // C-style varargs (`...` in a signature) can be detected.
    static_assert(!ct::has_varargs(foo{}), "");

    // callable_traits::is_ambiguous yields std::true_type 
    // only when the callable is overloaded or templated.
    static_assert(!ct::is_ambiguous(foo{}), "");

    // callable_traits::can_invoke allows us to preview whether
    // std::invoke will compile with the given arguments. Keep
    // in mind that failing cases must be SFINAE-friendly (i.e.
    // any failing static_asserts can still be tripped). Note: The
    // same is true for min_arity and max_arity on function objects.
    static_assert(ct::can_invoke(foo{}, 1, 'a', 3.0), "");
    // no error:     std::invoke(foo{}, 1, 'a', 3.0);

    static_assert(!ct::can_invoke(foo{}, nullptr), "");
    // error:         std::invoke(foo{}, nullptr);

    // callable_traits::bind_expr parses bind expressions. Nested bind
    // expressions are also handled, but are not shown in this example.
    using bind_expression = decltype(ct::bind_expr(foo{}, _1, _1, _1));

    // int is chosen as the expected argument for the bind expression
    // because it's the best fit for all three placeholder slots.
    static_assert(std::is_same<
        ct::args<bind_expression>,
        std::tuple<int>
    >{}, "");

    // Unfortunately, we can't do type manipulations with std::bind directly,
    // because the ISO C++ standard says very little about the return type of
    //std::bind. So, we call std::bind in the same way we called ct::bind_expr
    // above. If there is interest within Boost, this functionality can be
    // integrated into Boost.Bind (on which this implementation is loosely based).
    auto bind_obj = std::bind(foo{}, _1, _1, _1);

    // callable_traits can facilitate the construction of std::function objects.
    auto fn = std::function<ct::signature<bind_expression>>{ bind_obj };
    fn(0);

    // For function objects, the following checks are determined by the 
    // qualifiers on operator(). 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_reference_qualified(foo{}), "");
    static_assert(!ct::is_rvalue_reference_qualified(foo{}), "");

    return 0;
}

License

Please see LICENSE.md.

Description
Mirrored via gitea-mirror
Readme 2.3 MiB
Languages
C++ 97.6%
CMake 2.1%
Shell 0.2%
HTML 0.1%