Библиотека compile-time аннотаций
От: TarasKo Голландия  
Дата: 13.01.13 15:27
Оценка: 17 (2)
Сразу пример с несколькими сценариями использования:

struct A
{
// Определяем в структуре 3 поля
// int int_field_;
// std::string string_field_;
// double no_ann_field_;

// Первые два поля имеют аннотации, последнее нет.

    AUX_DECLARE_AND_ANNOTATE(
        ((int, int_field_,
            ((int_annotation, 24.0))
            ((string_annotation, "Privet"))
        ))
        ((std::string, string_field_,
            ((no_serialization, std::true_type()))
            ((no_hash, std::true_type()))
        ))
        ((double, no_ann_field_, BOOST_PP_SEQ_NIL))
      )
};

// Определим метафункцию позволяющую определить есть ли в типе с аннотациями, аннотация no_hash
AUX_DEFINE_MEMBER_DETECTOR(no_hash)

// Визитор для boost::fusion::for_each, см. код ниже
struct dump_members
{
    template<typename MemberType, typename AnnotationsType>
    void operator()(const aux::annotated_member<MemberType, AnnotationsType>& member) const
    {
        cout << "Member value: " << member.value_ << endl;

        // We can make compile time check here whether member has specific annotation
        cout << "\tHas no_hash annotation: " << has_no_hash<AnnotationsType>::value << endl;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    A a;

    // Use case 1:
    // Явно обращаемся к члену и к типу содержащему его аннотации
    a.int_field_ = 100;
    a.string_field_ = "string field";
    a.no_ann_field_ = 20.;

    A::annotations_for_int_field_ a1;
    A::annotations_for_string_field_ a2;
    A::annotations_for_no_ann_field_ a3;

    cout << "Value of int_annotation for A::int_field_" << a1.int_annotation << endl;    

    // Use case 2:
    // Метафункция проверяющая являются ли поля в типе аннотированными
    cout << "has_annotations<A> = " << aux::has_annotations<A>::value << endl;
    cout << "has_annotations<int> = " << aux::has_annotations<int>::value << endl;

    // Use case 3:
    // Получение членов структуры и связанных с ними аннотаций в виде кортежа, 
    boost::fusion::for_each(a.annotated_tuple(), dump_members());
    
    return 0;
}


А вот реализация
#pragma once

/// @file annotations.hpp

#include <boost/fusion/container/vector.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/adapted/struct/define_struct_inline.hpp>

#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/transform.hpp>
#include <boost/preprocessor/comma_if.hpp>
#include <boost/preprocessor/identity.hpp>
#include <boost/preprocessor/empty.hpp>

#include <boost/mpl/has_xxx.hpp>

namespace aux {

/// Bound together 
template<typename MemberType, typename AnnotationsType>
struct annotated_member
{
    typedef AnnotationsType annotations_type;
    typedef MemberType member_type;

    MemberType& value_;

    annotated_member(MemberType& value) : value_(value) {}
};

//--------------------- USER LEVEL MACROSES --------------------------------------------

/// Declare and annotate member with specified types
/// @code
///struct A
///{
///    AUX_DECLARE_AND_ANNOTATE(
///        ((int, int_field_,
///            ((int_annotation, 24.0))
///            ((string_annotation, "Privet"))
///        ))
///        ((std::string, string_field_,
///            ((no_serialization, std::true_type()))
///            ((no_hash, std::true_type()))
///        ))
///        ((double, no_ann_field_, BOOST_PP_SEQ_NIL))
///      )
//};
/// @endcode
#define AUX_DECLARE_AND_ANNOTATE(X) \
    typedef void annotated_tag; \
    BOOST_PP_SEQ_FOR_EACH_R(1, AUX_DETAIL_DECLARE_MEMBER, _, X) \
    BOOST_PP_SEQ_FOR_EACH_R(1, AUX_DETAIL_DECLARE_ANNOTATION_STRUCT, _, X) \
    AUX_DETAIL_DECLARE_MUTABLE_TUPLE_TYPE(X) \
    AUX_DETAIL_DECLARE_CONST_TUPLE_TYPE(X) 


/// Define metafunction that become true if type member were defined using AUX_DECLARE_AND_ANNOTATE
BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_annotations, annotated_tag, false);

/// Stolen from http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Member_Detector
/// Define metafunction that detect presence of some member in structure
#define AUX_DEFINE_MEMBER_DETECTOR(X)                                               \
template<typename T> class has_##X {                                                \
    struct Fallback { int X; };                                                     \
    struct Derived : T, Fallback { };                                               \
                                                                                    \
    template<typename U, U> struct Check;                                           \
                                                                                    \
    typedef char ArrayOfOne[1];                                                     \
    typedef char ArrayOfTwo[2];                                                     \
                                                                                    \
    template<typename U> static ArrayOfOne & func(Check<int Fallback::*, &U::X> *); \
    template<typename U> static ArrayOfTwo & func(...);                             \
  public:                                                                           \
    typedef has_##X type;                                                           \
    enum { value = sizeof(func<Derived>(0)) == 2 };                                 \
};

//--------------------- IMPLEMENTATION LEVEL MACROSES --------------------------------------------

// Define type that will be used for tuple. Better to use C++11 template aliasing instead of macro
#define AUX_DETAIL_TUPLE_TYPE boost::fusion::vector

// Accessors for top level tuple
#define AUX_DETAIL_L1_TYPE(tup) BOOST_PP_TUPLE_ELEM(3, 0, tup)
#define AUX_DETAIL_L1_MEMBER(tup) BOOST_PP_TUPLE_ELEM(3, 1, tup)
#define AUX_DETAIL_L1_ANN_SEQ(tup) BOOST_PP_TUPLE_ELEM(3, 2, tup)

// Accessort for annotations level tuple
#define AUX_DETAIL_L2_NAME(tup) BOOST_PP_TUPLE_ELEM(2, 0, tup)
#define AUX_DETAIL_L2_VALUE(tup) BOOST_PP_TUPLE_ELEM(2, 1, tup)

// Produce name for annotation structure
#define AUX_DETAIL_ANN_NAME(tup) BOOST_PP_CAT(annotations_for_, AUX_DETAIL_L1_MEMBER(tup))

// Declare member using top level tuple
#define AUX_DETAIL_DECLARE_MEMBER(r, data, tup) AUX_DETAIL_L1_TYPE(tup) AUX_DETAIL_L1_MEMBER(tup);

#if !defined(AUX_USE_TUPLE_FOR_ANNOTATIONS)

// Produce colon on false and comma on true
#define AUX_DETAIL_COLON_OR_COMMA(cond) BOOST_PP_IF(cond, BOOST_PP_COMMA, BOOST_PP_IDENTITY(:))()

// Produce annotation initializer list for annotation structure constructor
#define AUX_DETAIL_INITIALIZER_LIST(r, data, i, tup) AUX_DETAIL_COLON_OR_COMMA(i) AUX_DETAIL_L2_NAME(tup)(AUX_DETAIL_L2_VALUE(tup))

// Produce declaration of annotation member
#define AUX_DETAIL_ANNOTATIONS_LIST(r, data, i, tup) decltype(AUX_DETAIL_L2_VALUE(tup)) AUX_DETAIL_L2_NAME(tup);

// Declare annotation struct using tuple
#define AUX_DETAIL_DECLARE_ANNOTATION_STRUCT(r, data, tup) \
    struct AUX_DETAIL_ANN_NAME(tup) { \
        AUX_DETAIL_ANN_NAME(tup) () \
            BOOST_PP_SEQ_FOR_EACH_I_R(r, AUX_DETAIL_INITIALIZER_LIST, _, AUX_DETAIL_L1_ANN_SEQ(tup)) {} \
        BOOST_PP_SEQ_FOR_EACH_I_R(r, AUX_DETAIL_ANNOTATIONS_LIST, _, AUX_DETAIL_L1_ANN_SEQ(tup)) \
    };

#else

// TODO: Initialize annotations with provided values

#define AUX_DETAIL_TRANSFORM_TO_FUSION_SEQ(d, data, tup) decltype(AUX_DETAIL_L2_VALUE(tup)), AUX_DETAIL_L2_NAME(tup)

#define AUX_DETAIL_DECLARE_ANNOTATION_STRUCT(r, data, tup) \
    BOOST_FUSION_DEFINE_STRUCT_INLINE(AUX_DETAIL_ANN_NAME(tup), BOOST_PP_SEQ_TRANSFORM(AUX_DETAIL_TRANSFORM_TO_FUSION_SEQ, _, AUX_DETAIL_L1_ANN_SEQ(tup)))

#endif

// Produce ", member" or "member" if i is 0
#define AUX_DETAIL_ENUM_MEMBERS(r, data, i, tup) BOOST_PP_COMMA_IF(i) AUX_DETAIL_L1_MEMBER(tup)

#define AUX_DETAIL_ANNOTATED_MEMBER(r, const_or_empty, i, tup) BOOST_PP_COMMA_IF(i) aux::annotated_member<const_or_empty() AUX_DETAIL_L1_TYPE(tup), AUX_DETAIL_ANN_NAME(tup)>

#define AUX_DETAIL_DECLARE_MUTABLE_TUPLE_TYPE(X) \
    typedef AUX_DETAIL_TUPLE_TYPE<BOOST_PP_SEQ_FOR_EACH_I(AUX_DETAIL_ANNOTATED_MEMBER, BOOST_PP_EMPTY, X)> annotated_tuple_type; \
    annotated_tuple_type annotated_tuple() { return annotated_tuple_type(BOOST_PP_SEQ_FOR_EACH_I(AUX_DETAIL_ENUM_MEMBERS, _, X)); }

#define AUX_DETAIL_DECLARE_CONST_TUPLE_TYPE(X) \
    typedef AUX_DETAIL_TUPLE_TYPE<BOOST_PP_SEQ_FOR_EACH_I(AUX_DETAIL_ANNOTATED_MEMBER, BOOST_PP_IDENTITY(const), X)> const_annotated_tuple_type; \
    const_annotated_tuple_type annotated_tuple() const { return const_annotated_tuple_type(BOOST_PP_SEQ_FOR_EACH_I(AUX_DETAIL_ENUM_MEMBERS, _, X)); }

} // namespace aux
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.