Skip to content

Commit

Permalink
Clean up and generalize code
Browse files Browse the repository at this point in the history
- Split up code into multiple files
- Better names for internal/helper classes
- Expose function_traits, member_pointer_traits, functor_traits
  which are used by callable_traits and might be useful individually
- Handle cv qualification more consistently
- Handle member function qualifiers
- Use constexpr instead of const
- Handle class static constant definitions correctly
  • Loading branch information
sth committed Aug 11, 2016
1 parent 3792ebf commit acb9f43
Show file tree
Hide file tree
Showing 9 changed files with 470 additions and 104 deletions.
3 changes: 2 additions & 1 deletion SConstruct
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

test_src = Split('''
test/driver.cpp
test/driver.cpp
test/function_test.cpp
test/callable_test.cpp
''')

Expand Down
94 changes: 28 additions & 66 deletions callable.hpp
Original file line number Diff line number Diff line change
@@ -1,91 +1,52 @@

#if !defined(STHCXX_CALLABLE_HPP_INCLUDED)
#define STHCXX_CALLABLE_HPP_INCLUDED
#if !defined(CALLABLE_CALLABLE_HPP_INCLUDED)
#define CALLABLE_CALLABLE_HPP_INCLUDED

#include <stddef.h>
#include <functional>
#include "helpers.hpp"
#include "function.hpp"
#include "member_function.hpp"
#include "functor.hpp"

// There are three basic kinds of callable types
// function types
struct function_tag {};
// function pointer types
struct function_ptr_tag {};
// classes with operator()
struct functor_tag {};

namespace detail {

/** Count the number of types given to the template */
template<typename... Types>
struct tva_count;

template<>
struct tva_count<> {
static const size_t value = 0;
};

template<typename Type, typename... Types>
struct tva_count<Type, Types...> {
static const size_t value = tva_count<Types...>::value + 1;
};


/** Get the nth type given to the template */
template<size_t n, typename... Types>
struct tva_n;

template<size_t N, typename Type, typename... Types>
struct tva_n<N, Type, Types...> : tva_n<N-1, Types...> {
};

template<typename Type, typename... Types>
struct tva_n<0, Type, Types...> {
typedef Type type;
};


/** Define traits for a function type */
template<typename Fun>
struct callable_traits_fn;

template<typename Ret, typename... Args>
struct callable_traits_fn<Ret (Args...)> {
typedef Ret function_type(Args...);
typedef Ret return_type;
static const size_t argc;

template<size_t N>
using argument_type = typename tva_n<N, Args...>::type;
};

template<typename Ret, typename... Args>
const size_t callable_traits_fn<Ret (Args...)>::argc = tva_count<Args...>::value;

namespace detail {

/** Define traits for a operator() member function pointer type */
template<typename MemFun>
struct callable_traits_memfnp;

template<typename Class, typename Ret, typename... Args>
struct callable_traits_memfnp<Ret (Class::*)(Args...)> : callable_traits_fn<Ret (Args...)> {
};

template<typename Class, typename Ret, typename... Args>
struct callable_traits_memfnp<Ret (Class::*)(Args...) const> : callable_traits_fn<Ret (Args...)> {
};


// classes with operator()
template<typename Callable>
struct callable_traits_d : detail::callable_traits_memfnp<decltype(&Callable::operator())> {
struct callable_traits : functor_traits<Callable> {
typedef functor_tag callable_category;
};

// functions
template<typename Ret, typename... Args>
struct callable_traits_d<Ret (Args...)> : detail::callable_traits_fn<Ret (Args...)> {
struct callable_traits<Ret (Args...)> : function_traits<Ret (Args...)> {
typedef function_tag callable_category;
};

// function pointers
template<typename Ret, typename... Args>
struct callable_traits_d<Ret (*)(Args...)> : detail::callable_traits_fn<Ret (Args...)> {
struct callable_traits<Ret (*)(Args...)> : function_traits<Ret (Args...)> {
typedef function_ptr_tag callable_category;
};

// std::function specializations
/*
template<typename Ret, typename... Args>
struct callable_traits_d<std::function<Ret (Args...)>> : detail::callable_traits_fn<Ret (Args...)> {
struct callable_traits_d<std::function<Ret (Args...)>> : function_traits<Ret (Args...)> {
typedef functor_tag callable_category;
};
*/

} // namespace detail

Expand All @@ -94,15 +55,16 @@ struct callable_traits_d<std::function<Ret (Args...)>> : detail::callable_traits

/** Traits for a callable (function/functor/lambda/...) */
template<typename Callable>
struct callable_traits : detail::callable_traits_d<typename std::remove_reference<Callable>::type> {
struct callable_traits : detail::callable_traits<detail::remove_cvref_t<Callable>> {
};


/** Convert a callable to a std::function<> */
template<typename Callable>
std::function<typename callable_traits<Callable>::function_type> to_stdfunction(Callable fun) {
std::function<typename callable_traits<Callable>::function_type> stdfun(std::forward<Callable>(fun));
return stdfun;
}

#endif // STHCXX_CALLABLE_HPP_INCLUDED
#endif // CALLABLE_CALLABLE_HPP_INCLUDED

43 changes: 43 additions & 0 deletions function.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

#if !defined(CALLABLE_FUNCTION_HPP_INCLUDED)
#define CALLABLE_FUNCTION_HPP_INCLUDED

#include "helpers.hpp"
#include <cstddef>

namespace detail {

namespace {

/** Define traits for a function type */
template<typename Fun>
struct function_traits;

template<typename Ret, typename... Args>
struct function_traits<Ret (Args...)> {
typedef Ret function_type(Args...);
typedef Ret return_type;
static constexpr size_t argc = types_count<Args...>::value;

template<size_t N>
using argument_type = typename types_n<N, Args...>::type;
};

template<typename Ret, typename... Args>
const size_t function_traits<Ret (Args...)>::argc;

} // namespace

} // namespace detail


template<typename Func>
struct function_traits : detail::function_traits<detail::remove_cvref_t<Func>> {
};

template<typename Func>
struct function_traits<Func*> : detail::function_traits<detail::remove_cvref_t<Func>> {
};

#endif // CALLABLE_FUNCTION_HPP_INCLUDED

28 changes: 28 additions & 0 deletions functor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

#if !defined(CALLABLE_FUNCTOR_HPP_INCLUDED)
#define CALLABLE_FUNCTOR_HPP_INCLUDED

#include "helpers.hpp"
#include "function.hpp"
#include "member_function.hpp"

namespace detail {

template<typename Class>
using call_operator_traits = member_function_traits<decltype(&Class::operator())>;

// classes with operator()
template<typename Class>
struct functor_traits : function_traits<typename call_operator_traits<Class>::function_type> {
typedef call_operator_traits<Class> call_operator;
};

} // namespace detail


template<typename Class>
struct functor_traits : detail::functor_traits<detail::remove_cvref_t<Class>> {
};

#endif // CALLABLE_FUNCTOR_HPP_INCLUDED

66 changes: 66 additions & 0 deletions helpers.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@

#if !defined(CALLABLE_HELPERS_HPP_INCLUDED)
#define CALLABLE_HELPERS_HPP_INCLUDED

#include <cstddef>

namespace detail {

/** Remove reference and cv qualification */
template<typename T>
using remove_cvref_t = typename std::remove_cv< typename std::remove_reference<T>::type >::type;


/** Count the number of types given to the template */
template<typename... Types>
struct types_count;

template<>
struct types_count<> {
static constexpr std::size_t value = 0;
};


template<typename Type, typename... Types>
struct types_count<Type, Types...> {
static constexpr std::size_t value = types_count<Types...>::value + 1;
};


/** Get the nth type given to the template */
template<std::size_t n, typename... Types>
struct types_n;

template<std::size_t N, typename Type, typename... Types>
struct types_n<N, Type, Types...> : types_n<N-1, Types...> {
};

template<typename Type, typename... Types>
struct types_n<0, Type, Types...> {
typedef Type type;
};


/** Test if a type is in a list given types */
template<typename Q, typename... Ts>
struct types_has;

template<typename Q>
struct types_has<Q> {
static constexpr bool value = false;
};

template<typename Q, typename... Ts>
struct types_has<Q, Q, Ts...> {
static constexpr bool value = true;
};

template<typename Q, typename T, typename... Ts>
struct types_has<Q, T, Ts...> : types_has<Q, Ts...> {
};


} // namespace detail

#endif // CALLABLE_HELPERS_HPP_INCLUDED

Loading

0 comments on commit acb9f43

Please sign in to comment.