-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
experimental impelementation of type traits and type deduction
- Loading branch information
Showing
10 changed files
with
1,018 additions
and
6 deletions.
There are no files selected for viewing
Binary file not shown.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#include <tuple> | ||
#include <iostream> | ||
#include <typeinfo> | ||
|
||
template <typename... Types> | ||
constexpr std::tuple<Types...> my_make_tuple(Types&&...t) { | ||
return std::tuple<Types...>(std::forward<Types>(t)...); | ||
} | ||
|
||
struct st { | ||
int i,j; | ||
double d; | ||
static constexpr auto x = my_make_tuple(&st::i,&st::j, &st::d); | ||
}; | ||
|
||
int main() { | ||
st t; | ||
|
||
std::cout << typeid(st::x).name() << std::endl; | ||
|
||
//int st::* x = std::get<0>(st::x); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
/* | ||
* Custom tuple implementation | ||
*/ | ||
|
||
#ifndef MXX_MEMBER_TUPLE | ||
#define MXX_MEMBER_TUPLE | ||
|
||
#include <cstddef> // for size_t | ||
#include <utility> // for std::forward | ||
|
||
template <typename T> | ||
struct type_wrap { | ||
typedef T type; | ||
}; | ||
|
||
template <size_t N, typename U> | ||
struct member { | ||
U m; | ||
|
||
constexpr member() : m() {}; | ||
constexpr member(U&& u) : m(u) {}; | ||
constexpr member(const U& u) : m(u) {}; | ||
|
||
U& get() { | ||
return m; | ||
} | ||
const U& get() const { | ||
return m; | ||
} | ||
}; | ||
|
||
template <size_t I, typename... Types> | ||
struct type_at; | ||
|
||
template <typename Type> | ||
struct type_at<0, Type> : type_wrap<Type> {}; | ||
|
||
template <typename Type, typename... Types> | ||
struct type_at<0, Type, Types...> : type_wrap<Type> {}; | ||
|
||
template <size_t I, typename Type, typename... Types> | ||
struct type_at<I, Type, Types...> : type_at<I-1, Types...> {}; | ||
|
||
|
||
// template sequence of size_t | ||
template <size_t... S> | ||
struct seq_ {}; | ||
|
||
template <size_t N, size_t I = 0, typename Seq = seq_<>> | ||
struct seq; | ||
|
||
template <size_t N, size_t I, size_t... Seq> | ||
struct seq<N, I, seq_<Seq...>> : seq<N, I+1, seq_<Seq..., I>> {}; | ||
|
||
template <size_t N, size_t... Seq> | ||
struct seq<N, N, seq_<Seq...>> : type_wrap<seq_<Seq...>> {}; | ||
|
||
template <typename Seq, typename... Types> | ||
struct member_tuple_impl {}; | ||
|
||
// using flat multiple inheritance | ||
// and unpacking of the sequence | ||
template <size_t... Seq, typename... Types> | ||
struct member_tuple_impl<seq_<Seq...>, Types...> : member<Seq, Types>... { | ||
constexpr member_tuple_impl() : member<Seq, Types>()... {} | ||
constexpr member_tuple_impl(Types&&...t) : member<Seq, Types>(std::forward<Types>(t))... {} | ||
}; | ||
|
||
template <typename... Types> | ||
struct member_tuple : member_tuple_impl<typename seq<sizeof...(Types)>::type, Types...> { | ||
|
||
using base_type = member_tuple_impl<typename seq<sizeof...(Types)>::type, Types...>; | ||
|
||
template <size_t I> | ||
typename type_at<I, Types...>::type& get() { | ||
return member<I, typename type_at<I, Types...>::type>::get(); | ||
} | ||
template <size_t I> | ||
const typename type_at<I, Types...>::type& get() const { | ||
return member<I, typename type_at<I, Types...>::type>::get(); | ||
} | ||
|
||
constexpr member_tuple() : base_type() {}; | ||
constexpr member_tuple(Types&&... t) : base_type(std::forward<Types>(t)...) {}; | ||
}; | ||
|
||
/* | ||
template <typename... Types> | ||
constexpr member_tuple<size_t, Types...> declare_type(Types&&... t) { | ||
return member_tuple<size_t, Types...>(sizeof...(Types),std::forward<Types>(t)...); | ||
}; | ||
*/ | ||
|
||
template <typename... Types> | ||
constexpr std::tuple<Types...> declare_type(Types&&... t) { | ||
return std::tuple<Types...>(std::forward<Types>(t)...); | ||
}; | ||
|
||
#endif // MXX_MEMBER_TUPLE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
|
||
#include <cstddef> | ||
#include <iostream> | ||
#include <utility> | ||
#include <tuple> | ||
#include <type_traits> | ||
#include <typeinfo> | ||
#include <limits> | ||
|
||
#include <mxx/comm.hpp> | ||
#include <mxx/datatypes.hpp> | ||
|
||
#include "type_traits.hpp" | ||
#include "member_tuple.hpp" | ||
|
||
struct no_member { | ||
double d; | ||
int i; | ||
}; | ||
|
||
struct static_constexpr_obj { | ||
int i; | ||
double d; | ||
//char x[4]; | ||
|
||
static constexpr auto datatype = declare_type(&static_constexpr_obj::i, &static_constexpr_obj::d); | ||
}; | ||
|
||
|
||
struct static_const_obj { | ||
double d; | ||
int i; | ||
typedef static_const_obj baz; | ||
const static std::tuple<int baz::*, double baz::*> datatype; | ||
}; | ||
|
||
struct nonstatic_obj { | ||
int datatype; | ||
}; | ||
|
||
struct nonstatic_func { | ||
void datatype() { | ||
} | ||
}; | ||
|
||
struct static_func { | ||
static void datatype() {} | ||
}; | ||
|
||
struct multiple_funcs { | ||
void datatype() { } | ||
void datatype(int) { } | ||
int datatype(int, int) { return 0;} | ||
}; | ||
|
||
struct multiple_static_funcs { | ||
static void datatype() { } | ||
static void datatype(int) { } | ||
static int datatype(int, int) { return 0;} | ||
}; | ||
|
||
struct multi_mixed_funcs { | ||
static void datatype() { } | ||
static void datatype(float) { } | ||
void datatype(int) { } | ||
int datatype(int, int) { return 0;} | ||
}; | ||
|
||
|
||
// check if this has a constexpr member (TODO use laptop version) | ||
|
||
// is_simple_datatype<T>: if it declares its datatype and if all members are simple | ||
// builtin types are simple by default | ||
|
||
// need checker for has static object member (vs function) | ||
// MXX_HAS_STATIC_OBJECT_MEMBER() | ||
|
||
// buffer_tag, custom_buffer_tag, etc... | ||
|
||
#define PRINT_TYPE_TRAIT(TRAIT, TYPE) std::cout << "" # TRAIT " for type " # TYPE ": " << TRAIT < TYPE > ::value << std::endl; | ||
|
||
#define PRINT_TYPE_TRAIT_ALL(TRAIT) \ | ||
PRINT_TYPE_TRAIT(TRAIT, no_member) \ | ||
PRINT_TYPE_TRAIT(TRAIT, static_constexpr_obj) \ | ||
PRINT_TYPE_TRAIT(TRAIT, static_const_obj) \ | ||
PRINT_TYPE_TRAIT(TRAIT, nonstatic_obj) \ | ||
PRINT_TYPE_TRAIT(TRAIT, static_func) \ | ||
PRINT_TYPE_TRAIT(TRAIT, nonstatic_func) \ | ||
PRINT_TYPE_TRAIT(TRAIT, multiple_funcs) \ | ||
PRINT_TYPE_TRAIT(TRAIT, multiple_static_funcs) \ | ||
PRINT_TYPE_TRAIT(TRAIT, multi_mixed_funcs) | ||
|
||
int main(int argc, char *argv[]) | ||
{ | ||
PRINT_TYPE_TRAIT_ALL(has_static_object_member) | ||
PRINT_TYPE_TRAIT_ALL(has_static_function_member) | ||
|
||
PRINT_TYPE_TRAIT_ALL(has_function_member) | ||
|
||
// test for the overloaded functions: | ||
std::cout << "has_function_member: void(): " << has_function_member<multiple_funcs, void()>::value << std::endl; | ||
std::cout << "has_function_member: void(): " << has_function_member<multi_mixed_funcs, void()>::value << std::endl; | ||
std::cout << "has_function_member: void(): " << has_function_member<multiple_static_funcs, void()>::value << std::endl; | ||
|
||
std::cout << "has_static_function_member: void(): " << has_static_function_member<multiple_funcs, void()>::value << std::endl; | ||
std::cout << "has_static_function_member: void(): " << has_static_function_member<multi_mixed_funcs, void()>::value << std::endl; | ||
std::cout << "has_static_function_member: void(): " << has_static_function_member<multiple_static_funcs, void()>::value << std::endl; | ||
|
||
std::cout << typeid(static_cast<void(multiple_funcs::*)()>(&multiple_funcs::datatype)).name() << std::endl; | ||
|
||
std::cout << typeid(*static_cast<void(*)()>(multiple_static_funcs::datatype)).name() << std::endl; | ||
|
||
//.PRINT_TYPE_TRAIT_ALL(has_datatype_constexpr) | ||
|
||
|
||
/* | ||
std::cout << typeid(decltype(foo::datatype)).name() << std::endl; | ||
std::cout << "is const: " << std::is_const<decltype(foo::datatype)>::value << std::endl; | ||
std::cout << "is const: " << std::is_const<decltype(baz::datatype)>::value << std::endl; | ||
std::cout << "all are member: " << all_are<std::is_member_pointer, std::remove_const<decltype(foo::datatype)>::type>::value << std::endl; | ||
std::cout << "all are member: " << all_are<std::is_member_pointer, std::tuple<int foo::*, double foo::*>>::value << std::endl; | ||
std::cout << "all are member: " << are_all_member_pointer<decltype(baz::datatype)>::value << std::endl; | ||
std::cout << "is member ptr: "<< std::is_member_pointer<std::tuple_element<0, decltype(foo::datatype)>::type>::value << std::endl; | ||
std::cout << "is member ptr: "<< std::is_member_pointer<std::tuple_element<1, decltype(foo::datatype)>::type>::value << std::endl; | ||
std::cout << "tuple size: " << std::tuple_size<decltype(foo::datatype)>::value << std::endl; | ||
std::cout << " are all arith: " << all_are<std::is_arithmetic, std::tuple<int, float, char>>::value << std::endl; | ||
*/ | ||
|
||
return 0; | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
#ifndef MXX_EXPERIMENTAL_TYPE_TRAITS | ||
#define MXX_EXPERIMENTAL_TYPE_TRAITS | ||
|
||
#include <type_traits> | ||
#include <tuple> // for all_are tuple specializations | ||
|
||
#define MXX_DEFINE_HAS_STATIC_MEMBER_OBJECT(MEMBER_NAME) \ | ||
template <typename T, typename Enable = void> \ | ||
struct has_static_member_object_ ## MEMBER_NAME : std::false_type {}; \ | ||
\ | ||
template <typename T> \ | ||
struct has_static_member_object_ ## MEMBER_NAME <T, typename std::enable_if< \ | ||
!std::is_member_pointer<decltype(&T:: MEMBER_NAME )>::value \ | ||
&& !std::is_function<decltype(T :: MEMBER_NAME )>::value>::type> \ | ||
: std::true_type {}; \ | ||
|
||
|
||
#define MXX_DEFINE_HAS_MEMBER_OBJECT(MEMBER_NAME) \ | ||
template <typename T, typename Enable = void> \ | ||
struct has_member_object_ ## MEMBER_NAME : std::false_type {}; \ | ||
\ | ||
template <typename T> \ | ||
struct has_member_object_ ## MEMBER_NAME <T, typename std::enable_if< \ | ||
std::is_member_object_pointer<decltype(&T:: MEMBER_NAME )>::value>::type> \ | ||
: std::true_type {}; \ | ||
\ | ||
|
||
#define MXX_DEFINE_HAS_STATIC_MEMBER_FUNCTION(MEMBER_NAME) \ | ||
template <typename T, typename Sig = std::false_type, typename Enable = void> \ | ||
struct has_static_member_function_ ## MEMBER_NAME : std::false_type {}; \ | ||
\ | ||
template <typename T> \ | ||
struct has_static_member_function_ ## MEMBER_NAME \ | ||
<T, std::false_type, typename std::enable_if< \ | ||
std::is_function<decltype(T:: MEMBER_NAME )>::value>::type> \ | ||
: std::true_type {}; \ | ||
\ | ||
template <typename T, typename R, typename... Args> \ | ||
struct has_static_member_function_ ## MEMBER_NAME \ | ||
<T, R(Args...), typename std::enable_if< \ | ||
std::is_same<decltype(static_cast<R(*)(Args...)>(&T:: MEMBER_NAME )), \ | ||
R(*)(Args...)>::value>::type> \ | ||
: std::true_type {}; \ | ||
|
||
/* | ||
template <typename T> | ||
struct has_static_member : std::integral_constant<bool, | ||
has_static_member_object<T>::value | ||
|| has_static_member_function<T>::value> {}; | ||
*/ | ||
|
||
#define MXX_DEFINE_HAS_MEMBER_FUNCTION(MEMBER_NAME) \ | ||
template <typename T, typename Sig = std::false_type, typename Enable = void> \ | ||
struct has_member_function_ ## MEMBER_NAME : std::false_type {}; \ | ||
\ | ||
template <typename T> \ | ||
struct has_member_function_ ## MEMBER_NAME \ | ||
<T, std::false_type, typename std::enable_if< \ | ||
std::is_member_function_pointer<decltype(&T:: MEMBER_NAME )>::value>::type>\ | ||
: std::true_type {}; \ | ||
\ | ||
template <typename T, typename Func> \ | ||
struct has_member_function_ ## MEMBER_NAME <T, Func, typename std::enable_if< \ | ||
std::is_member_function_pointer< \ | ||
decltype(static_cast<Func T::*>(&T:: MEMBER_NAME ))>::value>::type> \ | ||
: std::true_type {}; \ | ||
\ | ||
|
||
#define MXX_DEFINE_MEMBER_TRAITS(MEMBER_NAME) \ | ||
MXX_DEFINE_HAS_MEMBER_OBJECT(MEMBER_NAME) \ | ||
MXX_DEFINE_HAS_STATIC_MEMBER_OBJECT(MEMBER_NAME) \ | ||
MXX_DEFINE_HAS_MEMBER_FUNCTION(MEMBER_NAME) \ | ||
MXX_DEFINE_HAS_STATIC_MEMBER_FUNCTION(MEMBER_NAME) | ||
|
||
/* | ||
template <typename T, typename Enable = void> | ||
struct has_datatype_constexpr : std::false_type {}; | ||
template <typename T> | ||
struct has_datatype_constexpr<T,typename std::enable_if< | ||
std::is_member_object_pointer<typename std::tuple_element<0,decltype(T::datatype)>::type>::value | ||
// the standard § 4.11 [conv.mem]: | ||
// guarantuees that `valid` pointer-to-member are always distinct from the | ||
// `null pointer to member` | ||
&& std::get<0>(T::datatype) != nullptr | ||
>::type> : std::true_type {}; | ||
*/ | ||
|
||
template <template <typename> class Trait, typename... Types> | ||
struct all_are; | ||
|
||
template <template<typename> class Trait, typename Type, typename... Types> | ||
struct all_are<Trait, Type, Types...> : std::integral_constant<bool, | ||
Trait<Type>::value && all_are<Trait, Types...>::value> {}; | ||
|
||
template <template<typename> class Trait, typename Type> | ||
struct all_are<Trait, Type> : std::integral_constant<bool, | ||
Trait<Type>::value> {}; | ||
|
||
// specialization for std::tuple | ||
template <template<typename> class Trait, typename... Types> | ||
struct all_are<Trait, std::tuple<Types...>> : std::integral_constant<bool, | ||
all_are<Trait, Types...>::value> {}; | ||
|
||
template <typename... T> | ||
struct are_all_member_pointer : std::false_type {}; | ||
|
||
template <typename... Types> | ||
struct are_all_member_pointer<std::tuple<Types...>> : all_are<std::is_member_pointer, Types...> {}; | ||
|
||
template <typename... Types> | ||
struct are_all_member_pointer<const std::tuple<Types...>> : all_are<std::is_member_pointer, Types...> {}; | ||
|
||
#endif // MXX_EXPERIMENTAL_TYPE_TRAITS |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.