Skip to content

Commit

Permalink
add visit_struct::get and get_name to the intrusive syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
cbeck88 committed Jul 25, 2017
1 parent ae42db0 commit 7c82568
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 4 deletions.
48 changes: 44 additions & 4 deletions include/visit_struct/visit_struct_intrusive.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,30 @@ struct Append<TypeList<Ts...>, T> {
template<class L, class T>
using Append_t = typename Append<L, T>::type;

// Cdr metafunction (cdr is a lisp function which returns the tail of a list)
template <class List>
struct Cdr;

template <typename T, typename... Ts>
struct Cdr<TypeList<T, Ts...>> {
typedef TypeList<Ts...> type;
};

template <class List>
using Cdr_t = typename Cdr<List>::type;

// Find metafunction (get the idx'th element)
template <class List, unsigned idx>
struct Find : Find<Cdr_t<List>, idx - 1> {};

template <typename T, typename... Ts>
struct Find<TypeList<T, Ts...>, 0> {
typedef T type;
};

template <class List, unsigned idx>
using Find_t = typename Find<List, idx>::type;

/***
* The "rank" template is a trick which can be used for
* certain metaprogramming techniques. It creates
Expand Down Expand Up @@ -140,7 +164,7 @@ struct member_ptr_helper {
static VISIT_STRUCT_CONSTEXPR T S::* get_ptr() { return member_ptr; }
};

// M should be a member_ptr_helper
// M should be derived from a member_ptr_helper
template <typename M>
struct member_helper {
template <typename V, typename S>
Expand Down Expand Up @@ -220,22 +244,38 @@ struct visitable <T,
// Apply to an instance
// S should be the same type as T modulo const and reference
template <typename V, typename S>
VISIT_STRUCT_CXX14_CONSTEXPR static void apply(V && v, S && s) {
static VISIT_STRUCT_CXX14_CONSTEXPR void apply(V && v, S && s) {
detail::structure_helper<typename T::Visit_Struct_Registered_Members_List__>::apply_visitor(std::forward<V>(v), std::forward<S>(s));
}

// Apply with two instances
template <typename V, typename S1, typename S2>
VISIT_STRUCT_CXX14_CONSTEXPR static void apply(V && v, S1 && s1, S2 && s2) {
static VISIT_STRUCT_CXX14_CONSTEXPR void apply(V && v, S1 && s1, S2 && s2) {
detail::structure_helper<typename T::Visit_Struct_Registered_Members_List__>::apply_visitor(std::forward<V>(v), std::forward<S1>(s1), std::forward<S2>(s2));
}

// Apply with no instance
template <typename V>
VISIT_STRUCT_CXX14_CONSTEXPR static void apply(V && v) {
static VISIT_STRUCT_CXX14_CONSTEXPR void apply(V && v) {
detail::structure_helper<typename T::Visit_Struct_Registered_Members_List__>::apply_visitor(std::forward<V>(v));
}

// Get value
template <int idx, typename S>
static VISIT_STRUCT_CONSTEXPR auto get_value(std::integral_constant<int, idx>, S && s)
-> decltype(std::forward<S>(s).*detail::Find_t<typename T::Visit_Struct_Registered_Members_List__, idx>::get_ptr())
{
return std::forward<S>(s).*detail::Find_t<typename T::Visit_Struct_Registered_Members_List__, idx>::get_ptr();
}

// Get name
template <int idx>
static VISIT_STRUCT_CONSTEXPR auto get_name(std::integral_constant<int, idx>)
-> decltype(detail::Find_t<typename T::Visit_Struct_Registered_Members_List__, idx>::member_name)
{
return detail::Find_t<typename T::Visit_Struct_Registered_Members_List__, idx>::member_name;
}

static VISIT_STRUCT_CONSTEXPR const bool value = true;
};

Expand Down
3 changes: 3 additions & 0 deletions test_visit_struct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ void debug_print(const T & t) {
static_assert(std::is_same<decltype(visit_struct::get<0>(std::declval<test_struct_one>())), int>::value, "");
static_assert(std::is_same<decltype(visit_struct::get<1>(std::declval<test_struct_one>())), float>::value, "");
static_assert(std::is_same<decltype(visit_struct::get<2>(std::declval<test_struct_one>())), std::string>::value, "");
// TODO: ^^ Should these types be int &&, float &&, std::string && ??? Why aren't they? Behavior should be consistent
// with the intrusive syntax.

static_assert(std::is_same<decltype(visit_struct::get_name<0, test_struct_one>()), const char (&)[2]>::value, "");
static_assert(std::is_same<decltype(visit_struct::get_name<1, test_struct_one>()), const char (&)[2]>::value, "");
static_assert(std::is_same<decltype(visit_struct::get_name<2, test_struct_one>()), const char (&)[2]>::value, "");
Expand Down
17 changes: 17 additions & 0 deletions test_visit_struct_intrusive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,16 @@ void debug_print(const T & t) {
std::cout << "}" << std::endl;
}

// tests

static_assert(std::is_same<decltype(visit_struct::get<0>(std::declval<test::foo>())), bool &&>::value, "");
static_assert(std::is_same<decltype(visit_struct::get<1>(std::declval<test::foo>())), int &&>::value, "");
static_assert(std::is_same<decltype(visit_struct::get<2>(std::declval<test::foo>())), float &&>::value, "");
static_assert(std::is_same<decltype(visit_struct::get_name<0, test::foo>()), const char *>::value, "");
static_assert(std::is_same<decltype(visit_struct::get_name<1, test::foo>()), const char *>::value, "");
static_assert(std::is_same<decltype(visit_struct::get_name<2, test::foo>()), const char *>::value, "");
// TODO: get_name should return const char (&)[]

int main() {
std::cout << __FILE__ << std::endl;

Expand All @@ -127,6 +137,13 @@ int main() {

debug_print(s);

assert(visit_struct::get<0>(s) == true);
assert(visit_struct::get<1>(s) == 5);
assert(visit_struct::get<2>(s) == 7.5f);
assert(visit_struct::get_name<0>(s) == std::string{"b"});
assert(visit_struct::get_name<1>(s) == std::string{"i"});
assert(visit_struct::get_name<2>(s) == std::string{"f"});

test_visitor_one vis;
visit_struct::apply_visitor(vis, s);

Expand Down

0 comments on commit 7c82568

Please sign in to comment.