-
-
Save nutbread/1a3d51df81577eac2df0 to your computer and use it in GitHub Desktop.
C++11 field iteration using macros and templates
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
#ifndef __FIELDS_H | |
#define __FIELDS_H | |
#include <cstddef> | |
#include <cstdint> | |
#include <type_traits> | |
#include <utility> | |
#include <tuple> | |
#include <boost/preprocessor/facilities/is_empty.hpp> | |
// Macro functions | |
// Note: if this macro is implemented without using Boost, the dependency can be removed | |
#define MACRO_VARARGS_IS_EMPTY(...) BOOST_PP_IS_EMPTY(__VA_ARGS__) | |
// Macro concat | |
#define FIELD_MACRO_CONCAT(a,b) FIELD_MACRO_CONCAT_INNER(a,b) | |
#define FIELD_MACRO_CONCAT_INNER(a,b) a ## b | |
// Macro recursion | |
#define FIELD_MACRO_EVAL(...) FIELD_MACRO_EVAL1(FIELD_MACRO_EVAL1(FIELD_MACRO_EVAL1(__VA_ARGS__))) | |
#define FIELD_MACRO_EVAL1(...) FIELD_MACRO_EVAL2(FIELD_MACRO_EVAL2(FIELD_MACRO_EVAL2(__VA_ARGS__))) | |
#define FIELD_MACRO_EVAL2(...) FIELD_MACRO_EVAL3(FIELD_MACRO_EVAL3(FIELD_MACRO_EVAL3(__VA_ARGS__))) | |
#define FIELD_MACRO_EVAL3(...) FIELD_MACRO_EVAL4(FIELD_MACRO_EVAL4(FIELD_MACRO_EVAL4(__VA_ARGS__))) | |
#define FIELD_MACRO_EVAL4(...) FIELD_MACRO_EVAL5(FIELD_MACRO_EVAL5(FIELD_MACRO_EVAL5(__VA_ARGS__))) | |
#define FIELD_MACRO_EVAL5(...) __VA_ARGS__ | |
// Fields | |
#define FIELD_DEFER_EMPTY(...) | |
#define FIELD_DEFER_EXPANSION(...) __VA_ARGS__ FIELD_DEFER_EMPTY() | |
#define FIELD_MEMBER_DEFERRED_FN() FIELD_MEMBER | |
#define FIELD_MEMBER_NEXT1(...) | |
#define FIELD_MEMBER_NEXT0(...) FIELD_DEFER_EXPANSION(FIELD_MEMBER_DEFERRED_FN)()( __VA_ARGS__ ) | |
#define FIELD_MEMBER(x,...) \ | |
FIELD_MEMBER_INNER( \ | |
FIELD_MACRO_CONCAT(FIELD_MEMBER_NEXT, MACRO_VARARGS_IS_EMPTY(__VA_ARGS__)), \ | |
x, \ | |
__VA_ARGS__ \ | |
) | |
#define FIELD_MEMBER_INNER(next,args,...) \ | |
FIELD_MEMBER_DECLARE args \ | |
next( __VA_ARGS__ ) | |
#define FIELD_MEMBER_DECLARE(x,y,...) x y; | |
#define FIELD_DESCRIPTOR_OFFSETOF_FN() offsetof | |
#define FIELD_DESCRIPTOR_DEFERRED_FN() FIELD_DESCRIPTOR | |
#define FIELD_DESCRIPTOR_NEXT1(...) | |
#define FIELD_DESCRIPTOR_NEXT0(cls,...) FIELD_DEFER_EXPANSION(FIELD_DESCRIPTOR_DEFERRED_FN)()(cls, __VA_ARGS__ ) | |
#define FIELD_DESCRIPTOR(cls,x,...) \ | |
FIELD_DESCRIPTOR_INNER( \ | |
cls, \ | |
FIELD_MACRO_CONCAT(FIELD_DESCRIPTOR_NEXT, MACRO_VARARGS_IS_EMPTY(__VA_ARGS__)), \ | |
x, \ | |
__VA_ARGS__ \ | |
) | |
#define FIELD_DESCRIPTOR_INNER(cls,next,args,...) \ | |
FIELD_DESCRIPTOR_DECLARE1 args \ | |
cls \ | |
FIELD_DESCRIPTOR_DECLARE2 args \ | |
next(cls, __VA_ARGS__ ) | |
#define FIELD_DESCRIPTOR_DECLARE1(x,y,...) \ | |
struct FIELD_MACRO_CONCAT(__FieldDescriptorHiddenClass_for_,y) final { \ | |
public: \ | |
static ::fields::FieldNameType field_name() { return #y; } \ | |
static constexpr const size_t field_offset() { return (FIELD_DEFER_EXPANSION(FIELD_DESCRIPTOR_OFFSETOF_FN)()( | |
#define FIELD_DESCRIPTOR_DECLARE2(x,y,...) \ | |
, y)); } \ | |
FIELD_DESCRIPTOR_DECLARE3(FIELD_MACRO_CONCAT(FIELD_DESCRIPTOR_DECLARE3_, MACRO_VARARGS_IS_EMPTY(__VA_ARGS__)), __VA_ARGS__ )\ | |
}; | |
#define FIELD_DESCRIPTOR_DECLARE3(fn,...) fn( __VA_ARGS__ ) | |
#define FIELD_DESCRIPTOR_DECLARE3_1(...) \ | |
static constexpr const ::fields::FieldFlags field_flags() { return 0; } | |
#define FIELD_DESCRIPTOR_DECLARE3_0(flags,...) \ | |
static constexpr const ::fields::FieldFlags field_flags() { return flags; } | |
#define FIELD_TUPLE_DEFERRED_FN() FIELD_TUPLE | |
#define FIELD_TUPLE_NEXT1(...) | |
#define FIELD_TUPLE_NEXT0(...) FIELD_DEFER_EXPANSION(FIELD_TUPLE_DEFERRED_FN)()( __VA_ARGS__ ) | |
#define FIELD_TUPLE(x,...) \ | |
FIELD_TUPLE_INNER( \ | |
FIELD_MACRO_CONCAT(FIELD_TUPLE_NEXT, MACRO_VARARGS_IS_EMPTY(__VA_ARGS__)), \ | |
x, \ | |
__VA_ARGS__ \ | |
) | |
#define FIELD_TUPLE_INNER(next,args,...) \ | |
FIELD_TUPLE_DECLARE args \ | |
next( __VA_ARGS__ ) | |
#define FIELD_TUPLE_DECLARE(x,y,...) \ | |
, std::tuple< x, FIELD_MACRO_CONCAT(__FieldDescriptorHiddenClass_for_,y) > | |
#define FIELDS(cls,...) \ | |
template <typename __FieldDescriptorHiddenType> friend class ::fields::FieldIteratorDescriptorGetter; \ | |
\ | |
FIELD_MACRO_EVAL(FIELD_MEMBER_NEXT0( __VA_ARGS__ )) \ | |
\ | |
FIELD_MACRO_EVAL(FIELD_DESCRIPTOR_NEXT0(cls, __VA_ARGS__ )) \ | |
\ | |
typedef std::tuple< cls \ | |
FIELD_MACRO_EVAL(FIELD_TUPLE_NEXT0(__VA_ARGS__ )) \ | |
> FieldIteratorDescriptor; | |
namespace fields { | |
typedef uint32_t FieldFlags; | |
typedef const char* FieldNameType; | |
template <typename Class, typename FieldReader> | |
class FieldIterator; | |
template <typename FieldIteratorT, size_t Index> | |
class FieldIteratorFunctions; | |
template <typename FieldIteratorT, size_t Index, bool HasFunction> | |
class FieldIteratorReadFunctionCaller; | |
template <typename Class> | |
class FieldIteratorClassIsTuple; | |
template <typename Class> | |
class FieldIteratorDescriptorGetter; | |
template <typename Type> | |
class Field; | |
template <typename FieldReader, typename Class> | |
inline void iterate(Class& object); | |
template <typename FieldReader, typename Class> | |
inline void iterate(Class&& object); | |
template <typename FieldReader, typename Class> | |
inline void iterate(const Class& object); | |
template <typename FieldReader, typename Class> | |
inline void iterate(Class& object, FieldReader& reader); | |
template <typename FieldReader, typename Class> | |
inline void iterate(Class&& object, FieldReader& reader); | |
template <typename FieldReader, typename Class> | |
inline void iterate(const Class& object, FieldReader& reader); | |
template <typename FieldReader, typename Class> | |
inline void iterate(Class& object, const FieldReader& reader); | |
template <typename FieldReader, typename Class> | |
inline void iterate(Class&& object, const FieldReader& reader); | |
template <typename FieldReader, typename Class> | |
inline void iterate(const Class& object, const FieldReader& reader); | |
template <typename FieldReader, typename Class> | |
inline void iterate(Class& object, FieldReader&& reader); | |
template <typename FieldReader, typename Class> | |
inline void iterate(Class&& object, FieldReader&& reader); | |
template <typename FieldReader, typename Class> | |
inline void iterate(const Class& object, FieldReader&& reader); | |
template <typename Class, typename FieldReader> | |
class FieldIterator final { | |
template <typename FieldIteratorT2, size_t Index2> friend class FieldIteratorFunctions; | |
template <typename FieldIteratorT2, size_t Index2, bool HasFunction2> friend class FieldIteratorReadFunctionCaller; | |
private: | |
typedef FieldReader FieldReaderType; | |
typedef typename FieldIteratorDescriptorGetter<Class>::Type FieldIteratorDescriptor; | |
typedef typename std::tuple_element<0, FieldIteratorDescriptor>::type ObjectType; | |
static constexpr const size_t FieldCount = std::tuple_size<FieldIteratorDescriptor>::value - 1; | |
typedef void (*Function)(FieldIterator& self); | |
typedef void (*ConstFunction)(FieldIterator& self); | |
union { | |
FieldReader* reader; | |
const FieldReader* const_reader; | |
} readers; | |
union { | |
ObjectType* object; | |
const ObjectType* const_object; | |
} objects; | |
union { | |
Function function; | |
ConstFunction const_function; | |
Function function_with_const_reader; | |
ConstFunction const_function_with_const_reader; | |
} functions; | |
FieldIterator() {} | |
~FieldIterator() {} | |
FieldIterator(FieldIterator&&) = delete; | |
FieldIterator(const FieldIterator&) = delete; | |
FieldIterator& operator = (FieldIterator&&) = delete; | |
FieldIterator& operator = (const FieldIterator&) = delete; | |
public: | |
static void iterate(ObjectType& object) { | |
FieldReader reader; | |
FieldIterator it; | |
it.readers.reader = &reader; | |
it.objects.object = &object; | |
it.functions.function = &FieldIteratorFunctions<FieldIterator, FieldCount>::function; | |
while (it.functions.function != nullptr) { | |
(it.functions.function)(it); | |
} | |
} | |
static void iterate(const ObjectType& object) { | |
FieldReader reader; | |
FieldIterator it; | |
it.readers.reader = &reader; | |
it.objects.const_object = &object; | |
it.functions.const_function = &FieldIteratorFunctions<FieldIterator, FieldCount>::const_function; | |
while (it.functions.const_function != nullptr) { | |
(it.functions.const_function)(it); | |
} | |
} | |
static void iterate(ObjectType& object, FieldReader& reader) { | |
FieldIterator it; | |
it.readers.reader = &reader; | |
it.objects.object = &object; | |
it.functions.function = &FieldIteratorFunctions<FieldIterator, FieldCount>::function; | |
while (it.functions.function != nullptr) { | |
(it.functions.function)(it); | |
} | |
} | |
static void iterate(const ObjectType& object, FieldReader& reader) { | |
FieldIterator it; | |
it.readers.reader = &reader; | |
it.objects.const_object = &object; | |
it.functions.const_function = &FieldIteratorFunctions<FieldIterator, FieldCount>::const_function; | |
while (it.functions.const_function != nullptr) { | |
(it.functions.const_function)(it); | |
} | |
} | |
static void iterate(ObjectType& object, const FieldReader& reader) { | |
FieldIterator it; | |
it.readers.const_reader = &reader; | |
it.objects.object = &object; | |
it.functions.function_with_const_reader = &FieldIteratorFunctions<FieldIterator, FieldCount>::function_with_const_reader; | |
while (it.functions.function_with_const_reader != nullptr) { | |
(it.functions.function_with_const_reader)(it); | |
} | |
} | |
static void iterate(const ObjectType& object, const FieldReader& reader) { | |
FieldIterator it; | |
it.readers.const_reader = &reader; | |
it.objects.const_object = &object; | |
it.functions.const_function_with_const_reader = &FieldIteratorFunctions<FieldIterator, FieldCount>::const_function_with_const_reader; | |
while (it.functions.const_function_with_const_reader != nullptr) { | |
(it.functions.const_function_with_const_reader)(it); | |
} | |
} | |
static void iterate(ObjectType& object, FieldReader&& reader) { | |
FieldIterator it; | |
it.readers.reader = &reader; | |
it.objects.object = &object; | |
it.functions.function = &FieldIteratorFunctions<FieldIterator, FieldCount>::function; | |
while (it.functions.function != nullptr) { | |
(it.functions.function)(it); | |
} | |
} | |
static void iterate(const ObjectType& object, FieldReader&& reader) { | |
FieldIterator it; | |
it.readers.reader = &reader; | |
it.objects.const_object = &object; | |
it.functions.const_function = &FieldIteratorFunctions<FieldIterator, FieldCount>::const_function; | |
while (it.functions.const_function != nullptr) { | |
(it.functions.const_function)(it); | |
} | |
} | |
}; | |
template <typename FieldIteratorT, size_t Index> | |
class FieldIteratorReadFunctionCaller<FieldIteratorT, Index, false> final { | |
template <typename FieldIteratorT2, size_t Index2> friend class FieldIteratorFunctions; | |
private: | |
FieldIteratorReadFunctionCaller() = delete; | |
~FieldIteratorReadFunctionCaller() = delete; | |
FieldIteratorReadFunctionCaller(FieldIteratorReadFunctionCaller&&) = delete; | |
FieldIteratorReadFunctionCaller(const FieldIteratorReadFunctionCaller&) = delete; | |
FieldIteratorReadFunctionCaller& operator = (FieldIteratorReadFunctionCaller&&) = delete; | |
FieldIteratorReadFunctionCaller& operator = (const FieldIteratorReadFunctionCaller&) = delete; | |
static inline void read_field(FieldIteratorT&) {} | |
static inline void read_const_field(FieldIteratorT&) {} | |
static inline void read_field_with_const_reader(FieldIteratorT&) {} | |
static inline void read_const_field_with_const_reader(FieldIteratorT&) {} | |
}; | |
template <typename FieldIteratorT, size_t Index> | |
class FieldIteratorReadFunctionCaller<FieldIteratorT, Index, true> final { | |
template <typename FieldIteratorT2, size_t Index2> friend class FieldIteratorFunctions; | |
private: | |
typedef typename FieldIteratorT::ObjectType ObjectType; | |
typedef typename FieldIteratorT::FieldIteratorDescriptor Descriptor; | |
typedef typename std::tuple_element<std::tuple_size<Descriptor>::value - Index, Descriptor>::type FieldTuple; | |
typedef typename std::tuple_element<0, FieldTuple>::type FieldType; | |
typedef typename std::tuple_element<1, FieldTuple>::type FieldDescriptor; | |
FieldIteratorReadFunctionCaller() = delete; | |
~FieldIteratorReadFunctionCaller() = delete; | |
FieldIteratorReadFunctionCaller(FieldIteratorReadFunctionCaller&&) = delete; | |
FieldIteratorReadFunctionCaller(const FieldIteratorReadFunctionCaller&) = delete; | |
FieldIteratorReadFunctionCaller& operator = (FieldIteratorReadFunctionCaller&&) = delete; | |
FieldIteratorReadFunctionCaller& operator = (const FieldIteratorReadFunctionCaller&) = delete; | |
static inline FieldType* get_value(ObjectType* object) { | |
return static_cast<FieldType*>( | |
static_cast<void*>( | |
static_cast<char*>(static_cast<void*>(object)) + | |
FieldDescriptor::field_offset() | |
) | |
); | |
} | |
static inline void read_field(FieldIteratorT& it) { | |
Field<FieldType> field( | |
FieldDescriptor::field_name(), | |
FieldDescriptor::field_flags(), | |
*get_value(it.objects.object) | |
); | |
it.readers.reader->read(field); | |
} | |
static inline void read_const_field(FieldIteratorT& it) { | |
Field<FieldType> field( | |
FieldDescriptor::field_name(), | |
FieldDescriptor::field_flags(), | |
*get_value(const_cast<ObjectType*>(it.objects.const_object)) | |
); | |
it.readers.reader->read(static_cast<const Field<FieldType>&>(field)); | |
} | |
static inline void read_field_with_const_reader(FieldIteratorT& it) { | |
Field<FieldType> field( | |
FieldDescriptor::field_name(), | |
FieldDescriptor::field_flags(), | |
*get_value(it.objects.object) | |
); | |
it.readers.const_reader->read(field); | |
} | |
static inline void read_const_field_with_const_reader(FieldIteratorT& it) { | |
Field<FieldType> field( | |
FieldDescriptor::field_name(), | |
FieldDescriptor::field_flags(), | |
*get_value(const_cast<ObjectType*>(it.objects.const_object)) | |
); | |
it.readers.const_reader->read(static_cast<const Field<FieldType>&>(field)); | |
} | |
}; | |
template <typename FieldIteratorT, size_t Index> | |
class FieldIteratorFunctions final { | |
template <typename Class2, typename FieldReader2> friend class FieldIterator; | |
template <typename FieldIteratorT2, size_t Index2> friend class FieldIteratorFunctions; | |
private: | |
typedef typename FieldIteratorT::FieldReaderType FieldReaderType; | |
typedef typename FieldIteratorT::FieldIteratorDescriptor Descriptor; | |
typedef typename std::tuple_element<std::tuple_size<Descriptor>::value - Index, Descriptor>::type FieldTuple; | |
typedef typename std::tuple_element<0, FieldTuple>::type FieldType; | |
FieldIteratorFunctions() = delete; | |
~FieldIteratorFunctions() = delete; | |
FieldIteratorFunctions(FieldIteratorFunctions&&) = delete; | |
FieldIteratorFunctions(const FieldIteratorFunctions&) = delete; | |
FieldIteratorFunctions& operator = (FieldIteratorFunctions&&) = delete; | |
FieldIteratorFunctions& operator = (const FieldIteratorFunctions&) = delete; | |
// has_reader_function is used to detect if a correct read(...) function is available | |
// if the function is not available, no read(...) function is called | |
template <typename T, typename U> | |
static constexpr auto has_reader_function(T t, U u) -> std::is_same< | |
decltype(t->read(*u)), | |
decltype(t->read(*u)) | |
>; | |
template <typename T, typename U> | |
static constexpr auto has_reader_function(...) -> std::false_type; | |
static void function(FieldIteratorT& it) { | |
typedef decltype(has_reader_function<FieldReaderType*, Field<FieldType>*>(0, 0)) HasReaderFunction; | |
FieldIteratorReadFunctionCaller<FieldIteratorT, Index, HasReaderFunction::value>::read_field(it); | |
it.functions.function = &FieldIteratorFunctions<FieldIteratorT, Index - 1>::function; | |
} | |
static void const_function(FieldIteratorT& it) { | |
typedef decltype(has_reader_function<FieldReaderType*, const Field<FieldType>*>(0, 0)) HasReaderFunction; | |
FieldIteratorReadFunctionCaller<FieldIteratorT, Index, HasReaderFunction::value>::read_const_field(it); | |
it.functions.const_function = &FieldIteratorFunctions<FieldIteratorT, Index - 1>::const_function; | |
} | |
static void function_with_const_reader(FieldIteratorT& it) { | |
typedef decltype(has_reader_function<const FieldReaderType*, Field<FieldType>*>(0, 0)) HasReaderFunction; | |
FieldIteratorReadFunctionCaller<FieldIteratorT, Index, HasReaderFunction::value>::read_field_with_const_reader(it); | |
it.functions.function_with_const_reader = &FieldIteratorFunctions<FieldIteratorT, Index - 1>::function_with_const_reader; | |
} | |
static void const_function_with_const_reader(FieldIteratorT& it) { | |
typedef decltype(has_reader_function<const FieldReaderType*, const Field<FieldType>*>(0, 0)) HasReaderFunction; | |
FieldIteratorReadFunctionCaller<FieldIteratorT, Index, HasReaderFunction::value>::read_const_field_with_const_reader(it); | |
it.functions.const_function_with_const_reader = &FieldIteratorFunctions<FieldIteratorT, Index - 1>::const_function_with_const_reader; | |
} | |
}; | |
template <typename FieldIteratorT> | |
class FieldIteratorFunctions<FieldIteratorT, 0> final { | |
template <typename Class2, typename FieldReader2> friend class FieldIterator; | |
template <typename FieldIteratorT2, size_t Index2> friend class FieldIteratorFunctions; | |
private: | |
FieldIteratorFunctions() = delete; | |
~FieldIteratorFunctions() = delete; | |
FieldIteratorFunctions(FieldIteratorFunctions&&) = delete; | |
FieldIteratorFunctions(const FieldIteratorFunctions&) = delete; | |
FieldIteratorFunctions& operator = (FieldIteratorFunctions&&) = delete; | |
FieldIteratorFunctions& operator = (const FieldIteratorFunctions&) = delete; | |
static void function(FieldIteratorT& it) { | |
it.functions.function = nullptr; | |
} | |
static void const_function(FieldIteratorT& it) { | |
it.functions.const_function = nullptr; | |
} | |
static void function_with_const_reader(FieldIteratorT& it) { | |
it.functions.function_with_const_reader = nullptr; | |
} | |
static void const_function_with_const_reader(FieldIteratorT& it) { | |
it.functions.const_function_with_const_reader = nullptr; | |
} | |
}; | |
template <typename Class> | |
class FieldIteratorClassIsTuple final : private std::true_type { | |
template <typename Class2> friend class FieldIteratorDescriptorGetter; | |
private: | |
FieldIteratorClassIsTuple() = delete; | |
~FieldIteratorClassIsTuple() = delete; | |
FieldIteratorClassIsTuple(FieldIteratorClassIsTuple&&) = delete; | |
FieldIteratorClassIsTuple(const FieldIteratorClassIsTuple&) = delete; | |
FieldIteratorClassIsTuple& operator = (FieldIteratorClassIsTuple&&) = delete; | |
FieldIteratorClassIsTuple& operator = (const FieldIteratorClassIsTuple&) = delete; | |
}; | |
template <typename... Args> | |
class FieldIteratorClassIsTuple<std::tuple<Args...> > final : private std::false_type { | |
template <typename Class2> friend class FieldIteratorDescriptorGetter; | |
private: | |
FieldIteratorClassIsTuple() = delete; | |
~FieldIteratorClassIsTuple() = delete; | |
FieldIteratorClassIsTuple(FieldIteratorClassIsTuple&&) = delete; | |
FieldIteratorClassIsTuple(const FieldIteratorClassIsTuple&) = delete; | |
FieldIteratorClassIsTuple& operator = (FieldIteratorClassIsTuple&&) = delete; | |
FieldIteratorClassIsTuple& operator = (const FieldIteratorClassIsTuple&) = delete; | |
}; | |
template <typename Class> | |
class FieldIteratorDescriptorGetter final { | |
template <typename Type2, typename DataType2> friend class FieldIterator; | |
private: | |
FieldIteratorDescriptorGetter() = delete; | |
~FieldIteratorDescriptorGetter() = delete; | |
FieldIteratorDescriptorGetter(FieldIteratorDescriptorGetter&&) = delete; | |
FieldIteratorDescriptorGetter(const FieldIteratorDescriptorGetter&) = delete; | |
FieldIteratorDescriptorGetter& operator = (FieldIteratorDescriptorGetter&&) = delete; | |
FieldIteratorDescriptorGetter& operator = (const FieldIteratorDescriptorGetter&) = delete; | |
typedef std::tuple<Class> DefaultType; | |
template <typename T> | |
static constexpr auto test(T*) -> typename std::conditional< | |
FieldIteratorClassIsTuple<typename T::FieldIteratorDescriptor>::value, | |
DefaultType, | |
typename T::FieldIteratorDescriptor | |
>::type; | |
template <typename T> | |
static constexpr auto test(...) -> DefaultType; | |
typedef decltype(test<Class>(0)) Type; | |
}; | |
template <typename Type2> | |
class Field final { | |
template <typename FieldIteratorT2, size_t Index2, bool HasFunction2> friend class FieldIteratorReadFunctionCaller; | |
public: | |
typedef Type2 Type; | |
private: | |
const FieldNameType name; | |
const FieldFlags flags; | |
Type& value; | |
Field() = delete; | |
~Field() {} | |
Field(Field&&) = delete; | |
Field(const Field&) = delete; | |
Field& operator = (Field&&) = delete; | |
Field& operator = (const Field&) = delete; | |
Field( | |
FieldNameType name, | |
FieldFlags flags, | |
Type& value | |
) : | |
name(name), | |
flags(flags), | |
value(value) | |
{ | |
} | |
public: | |
FieldNameType get_name() const { return this->name; } | |
FieldFlags get_flags() const { return this->flags; } | |
Type& get_value() { return this->value; } | |
const Type& get_value() const { return this->value; } | |
}; | |
template <typename FieldReader, typename Class> | |
inline void iterate(Class& object) { | |
FieldIterator<Class, FieldReader>::iterate(object); | |
} | |
template <typename FieldReader, typename Class> | |
inline void iterate(Class&& object) { | |
FieldIterator<Class, FieldReader>::iterate(object); | |
} | |
template <typename FieldReader, typename Class> | |
inline void iterate(const Class& object) { | |
FieldIterator<Class, FieldReader>::iterate(object); | |
} | |
template <typename FieldReader, typename Class> | |
inline void iterate(Class& object, FieldReader& reader) { | |
FieldIterator<Class, FieldReader>::iterate(object, reader); | |
} | |
template <typename FieldReader, typename Class> | |
inline void iterate(Class&& object, FieldReader& reader) { | |
FieldIterator<Class, FieldReader>::iterate(object, reader); | |
} | |
template <typename FieldReader, typename Class> | |
inline void iterate(const Class& object, FieldReader& reader) { | |
FieldIterator<Class, FieldReader>::iterate(object, reader); | |
} | |
template <typename FieldReader, typename Class> | |
inline void iterate(Class& object, const FieldReader& reader) { | |
FieldIterator<Class, FieldReader>::iterate(object, reader); | |
} | |
template <typename FieldReader, typename Class> | |
inline void iterate(Class&& object, const FieldReader& reader) { | |
FieldIterator<Class, FieldReader>::iterate(object, reader); | |
} | |
template <typename FieldReader, typename Class> | |
inline void iterate(const Class& object, const FieldReader& reader) { | |
FieldIterator<Class, FieldReader>::iterate(object, reader); | |
} | |
template <typename FieldReader, typename Class> | |
inline void iterate(Class& object, FieldReader&& reader) { | |
FieldIterator<Class, FieldReader>::iterate(object, std::forward<FieldReader>(reader)); | |
} | |
template <typename FieldReader, typename Class> | |
inline void iterate(Class&& object, FieldReader&& reader) { | |
FieldIterator<Class, FieldReader>::iterate(object, std::forward<FieldReader>(reader)); | |
} | |
template <typename FieldReader, typename Class> | |
inline void iterate(const Class& object, FieldReader&& reader) { | |
FieldIterator<Class, FieldReader>::iterate(object, std::forward<FieldReader>(reader)); | |
} | |
} // namespace fields | |
#endif // __FIELDS_H | |
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
#include "Fields.hpp" | |
#include <string> | |
#include <iostream> | |
class Test final { | |
private: | |
FIELDS( | |
Test, | |
(int, x), | |
(float, y, 1), | |
(double, z, 2), | |
(const char*, w, 3) | |
) | |
bool visible; | |
public: | |
Test() : | |
x(1), | |
y(2.5f), | |
z(3.75), | |
w("test"), | |
visible(false) | |
{} | |
}; | |
struct FieldReader final { | |
template <typename Type> | |
void read(fields::Field<Type>& field) { | |
std::cout << field.get_name() << "=" << field.get_value() << " (" << field.get_flags() << ")" << std::endl; | |
} | |
void read(fields::Field<int>& field) { | |
std::cout << field.get_name() << "=" << field.get_value() << " (" << field.get_flags() << ") [non-template-function-call]" << std::endl; | |
} | |
}; | |
int main(int, char**) { | |
Test test; | |
fields::iterate(test, FieldReader()); | |
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
/* | |
cls && g++ -Wall -std=c++11 -o FieldsTest.exe -I. FieldsTest.cpp && FieldsTest.exe | |
"%VS140COMNTOOLS%\..\..\VC\bin\vcvars32.bat" | |
cls && cl /nologo /EHsc /W4 FieldsTest.cpp /Fe:FieldsTest.cl.exe /I. && FieldsTest.cl.exe | |
*/ | |
#include "Fields.hpp" | |
#include <string> | |
#include <iostream> | |
#include <typeinfo> | |
#ifdef __GNUC__ | |
#include <cxxabi.h> | |
#endif | |
template <typename Type> | |
std::string get_type_name() { | |
std::string s; | |
const char* name = typeid(Type).name(); | |
#ifdef __GNUC__ | |
int status; | |
char* true_name = abi::__cxa_demangle(name, nullptr, nullptr, &status); | |
s = (status == 0 ? true_name : name); | |
free(true_name); | |
#else | |
s = name; | |
#endif | |
return s; | |
} | |
class Test final { | |
private: | |
FIELDS( | |
Test, | |
(int, x), | |
(float, y, 1), | |
(double, z, 2), | |
(const char*, w, 3) | |
) | |
bool visible; | |
public: | |
Test() : | |
x(1), | |
y(2.5f), | |
z(3.75), | |
w("test"), | |
visible(false) | |
{} | |
}; | |
class TestNoFields final {}; | |
class FieldReader final { | |
public: | |
int value; | |
FieldReader() : value(0) {} | |
template <typename Type> | |
void read(fields::Field<Type>& field) { | |
++this->value; | |
std::cout << " v1: " << get_type_name<Type>() << " " << field.get_name() << "=" << field.get_value() << " (" << field.get_flags() << ")" << std::endl; | |
} | |
template <typename Type> | |
void read(fields::Field<Type>& field) const { | |
std::cout << " v2: " << get_type_name<Type>() << " " << field.get_name() << "=" << field.get_value() << " (" << field.get_flags() << ")" << std::endl; | |
} | |
template <typename Type> | |
void read(const fields::Field<Type>& field) { | |
++this->value; | |
std::cout << " v3: " << get_type_name<Type>() << " " << field.get_name() << "=" << field.get_value() << " (" << field.get_flags() << ")" << std::endl; | |
} | |
template <typename Type> | |
void read(const fields::Field<Type>& field) const { | |
std::cout << " v4: " << get_type_name<Type>() << " " << field.get_name() << "=" << field.get_value() << " (" << field.get_flags() << ")" << std::endl; | |
} | |
}; | |
class FieldReaderStatic final { | |
public: | |
template <typename Type> | |
static void read(fields::Field<Type>& field) { | |
std::cout << " v5: " << get_type_name<Type>() << " " << field.get_name() << "=" << field.get_value() << " (" << field.get_flags() << ")" << std::endl; | |
} | |
template <typename Type> | |
static void read(const fields::Field<Type>& field) { | |
std::cout << " v6: " << get_type_name<Type>() << " " << field.get_name() << "=" << field.get_value() << " (" << field.get_flags() << ")" << std::endl; | |
} | |
}; | |
int main(int, char**) { | |
Test test; | |
TestNoFields test2; | |
FieldReader reader; | |
std::cout << "temp object, no reader" << std::endl; | |
fields::iterate<FieldReader>(Test()); | |
std::cout << std::endl << "temp object, temp reader" << std::endl; | |
fields::iterate(Test(), FieldReader()); | |
std::cout << std::endl << "temp object, non-const reader" << std::endl; | |
fields::iterate(Test(), reader); | |
std::cout << std::endl << "temp object, const reader" << std::endl; | |
fields::iterate(Test(), static_cast<const FieldReader&>(reader)); | |
std::cout << std::endl; | |
std::cout << std::endl << "non-const object, no reader" << std::endl; | |
fields::iterate<FieldReader>(test); | |
std::cout << std::endl << "non-const object, temp reader" << std::endl; | |
fields::iterate(test, FieldReader()); | |
std::cout << std::endl << "non-const object, non-const reader" << std::endl; | |
fields::iterate(test, reader); | |
std::cout << std::endl << "non-const object, const reader" << std::endl; | |
fields::iterate(test, static_cast<const FieldReader&>(reader)); | |
std::cout << std::endl; | |
std::cout << std::endl << "const object, no reader" << std::endl; | |
fields::iterate<FieldReader>(static_cast<const Test&>(test)); | |
std::cout << std::endl << "const object, temp reader" << std::endl; | |
fields::iterate(static_cast<const Test&>(test), FieldReader()); | |
std::cout << std::endl << "const object, non-const reader" << std::endl; | |
fields::iterate(static_cast<const Test&>(test), reader); | |
std::cout << std::endl << "const object, const reader" << std::endl; | |
fields::iterate(static_cast<const Test&>(test), static_cast<const FieldReader&>(reader)); | |
std::cout << std::endl; | |
std::cout << std::endl << "non-const object, static reader" << std::endl; | |
fields::iterate<FieldReaderStatic>(test); | |
std::cout << std::endl << "const object, static reader" << std::endl; | |
fields::iterate<FieldReaderStatic>(static_cast<const Test&>(test)); | |
std::cout << std::endl; | |
std::cout << std::endl << "non-const object (no fields), no reader" << std::endl; | |
fields::iterate<FieldReader>(test2); | |
std::cout << std::endl; | |
std::cout << std::endl << "reader.value=" << reader.value << std::endl; | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment