Last active
June 14, 2017 05:15
-
-
Save scraimer/2d954a89a1345d15736cade249878509 to your computer and use it in GitHub Desktop.
Get member if present, or default value if not
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
/* | |
* Goal: To have a class template that can recieve a template parameter of a class that either | |
has a member (e.g. _time) or doesn't have a member. | |
The class template has a function (e.g. get_time) which should return the value (e.g. _time), | |
or a default value (e.g. 22) | |
So far, I've got a class template 'getter_maker_t' that depending on its arguments can | |
will either create a class that returns the value, or returns a class that returns the default value. | |
TODO: | |
- Have a single expression for both case: when the class member is present, and when it is not | |
- Move it all into a namespace | |
*/ | |
#include <boost/convert/detail/has_member.hpp> | |
#include <boost/utility/enable_if.hpp> | |
#include <stdint.h> | |
#include <boost/type_traits/conditional.hpp> | |
#include <boost/type_traits/integral_constant.hpp> | |
template <typename T> | |
class message | |
{ | |
public: | |
T _header; // just public so I can set the value of _header._time in main. | |
}; | |
class reuters_header | |
{ | |
public: | |
uint64_t _time; | |
}; | |
class ebsu_header | |
{ | |
public: | |
// no time! | |
}; | |
BOOST_DECLARE_HAS_MEMBER(has_time, _time); | |
template <typename HEADER_T, typename MEMBER_T, MEMBER_T HEADER_T::*member_offset_ptr> | |
class ref_to_value | |
{ | |
public: | |
MEMBER_T const & _value; | |
ref_to_value( HEADER_T const & header ) : _value(header.*member_offset_ptr) { } | |
}; | |
template <typename HEADER_T, typename MEMBER_T, static MEMBER_T const & default_value> | |
class ref_to_default | |
{ | |
public: | |
MEMBER_T const & _value; | |
ref_to_default( HEADER_T const & header ) : _value(default_value) { } | |
}; | |
template <typename HEADER_T, typename MEMBER_T, static MEMBER_T const & default_value, MEMBER_T HEADER_T::*member_offset_ptr = nullptr, bool enable = false> | |
class getter_t | |
{ | |
public: | |
typedef typename boost::conditional<enable, ref_to_value<HEADER_T, MEMBER_T, member_offset_ptr>, ref_to_default<HEADER_T, MEMBER_T, default_value> >::type ref_t; | |
ref_t _ref; | |
getter_t( HEADER_T const & header ) : _ref(header) { } | |
MEMBER_T const & get_value() { return _ref._value; } | |
}; | |
template <typename HEADER_T, typename MEMBER_T, static MEMBER_T const & default_value, MEMBER_T HEADER_T::*member_offset_ptr = nullptr> | |
class getter_maker_t : public getter_t<HEADER_T, MEMBER_T, default_value, member_offset_ptr, has_time<HEADER_T>::value> | |
{ | |
public: | |
getter_maker_t( HEADER_T const & header ) : getter_t<HEADER_T, MEMBER_T, default_value, member_offset_ptr, has_time<HEADER_T>::value>(header) { } | |
}; | |
//// | |
template <typename HEADER_T, typename MEMBER_T, MEMBER_T HEADER_T::*ptr_to_member, typename enable = void> | |
struct get_ptr_to_member_or_null | |
{ | |
constexpr BOOST_STATIC_CONSTANT(auto, value = ptr_to_member); | |
}; | |
template <typename HEADER_T, typename MEMBER_T, MEMBER_T HEADER_T::*ptr_to_member> | |
struct get_ptr_to_member_or_null<HEADER_T, MEMBER_T, ptr_to_member, boost::enable_if<boost::true_type>::type > | |
{ | |
constexpr BOOST_STATIC_CONSTANT(auto, value = nullptr); | |
}; | |
// Before C++11, 'cannot use local types as template parameters'. So this is defined globally. | |
static uint64_t const default_value_for_missing_time = 22; | |
int main() | |
{ | |
message<reuters_header> rm; | |
rm._header._time = 33; | |
message<ebsu_header> em; | |
//// | |
// Iter #1: very different classes: ref_to_value, ref_to_default | |
ref_to_value<reuters_header, decltype(reuters_header::_time), &reuters_header::_time> gm( rm._header ); | |
auto a = gm._value; | |
ref_to_default<ebsu_header, uint64_t, default_value_for_missing_time> ge( em._header ); | |
auto b = ge._value; | |
//// | |
// Iter #2: same class, getter_t, but with very different parameters | |
getter_t<reuters_header, uint64_t, default_value_for_missing_time, &reuters_header::_time, true> g1( rm._header ); | |
auto c = g1.get_value(); | |
getter_t<ebsu_header, uint64_t, default_value_for_missing_time> g2( em._header); | |
auto d = g2.get_value(); | |
//// Iter #3: same class, with fewer and nearly the same parameters | |
getter_maker_t<reuters_header, uint64_t, default_value_for_missing_time, &reuters_header::_time> gm1( rm._header ); | |
auto e = gm1.get_value(); | |
getter_maker_t<ebsu_header, uint64_t, default_value_for_missing_time, nullptr> gm2( em._header ); | |
auto f = gm2.get_value(); | |
/// | |
getter_maker_t<reuters_header, uint64_t, default_value_for_missing_time, | |
get_ptr_to_member_or_null<reuters_header, uint64_t, &reuters_header::_time>::value | |
> gm10( rm._header ); | |
auto g = gm10.get_value(); | |
getter_maker_t<ebsu_header, uint64_t, default_value_for_missing_time, | |
get_ptr_to_member_or_null<ebsu_header, uint64_t, &ebsu_header::_time>::value | |
> gm11( em._header ); | |
auto h = gm11.get_value(); | |
return g + h; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment