আপনাকে যা করতে হবে তা হল ক্ষেত্রগুলি সম্পর্কে প্রতিস্থাপনের ডেটা তৈরি করা। এই ডেটা নেস্টেড ক্লাস হিসাবে সংরক্ষণ করা যেতে পারে।
প্রথমত, প্রিপ্রোসেসরে এটি লিখতে আরও সহজ এবং পরিষ্কার করার জন্য আমরা টাইপড এক্সপ্রেশন ব্যবহার করব। একটি টাইপযুক্ত এক্সপ্রেশন হ'ল একটি অভিব্যক্তি যা বন্ধনীতে টাইপ করে। সুতরাং লেখার পরিবর্তে int x
আপনি লিখবেন (int) x
। টাইপযুক্ত অভিব্যক্তিগুলিতে সহায়তা করার জন্য এখানে কয়েকটি হ্যান্ডি ম্যাক্রো রয়েছে:
#define REM(...) __VA_ARGS__
#define EAT(...)
// Retrieve the type
#define TYPEOF(x) DETAIL_TYPEOF(DETAIL_TYPEOF_PROBE x,)
#define DETAIL_TYPEOF(...) DETAIL_TYPEOF_HEAD(__VA_ARGS__)
#define DETAIL_TYPEOF_HEAD(x, ...) REM x
#define DETAIL_TYPEOF_PROBE(...) (__VA_ARGS__),
// Strip off the type
#define STRIP(x) EAT x
// Show the type without parenthesis
#define PAIR(x) REM x
এরপরে, আমরা REFLECTABLE
প্রতিটি ক্ষেত্রের ডেটা তৈরি করতে ম্যাক্রো সংজ্ঞায়িত করি (ক্ষেত্রটি নিজেই)। এই ম্যাক্রোটিকে এভাবে বলা হবে:
REFLECTABLE
(
(const char *) name,
(int) age
)
সুতরাং বুস্ট.পিপি ব্যবহার করে আমরা প্রতিটি যুক্তির মাধ্যমে পুনরাবৃত্তি করি এবং এর মতো ডেটা উত্পন্ন করি:
// A helper metafunction for adding const to a type
template<class M, class T>
struct make_const
{
typedef T type;
};
template<class M, class T>
struct make_const<const M, T>
{
typedef typename boost::add_const<T>::type type;
};
#define REFLECTABLE(...) \
static const int fields_n = BOOST_PP_VARIADIC_SIZE(__VA_ARGS__); \
friend struct reflector; \
template<int N, class Self> \
struct field_data {}; \
BOOST_PP_SEQ_FOR_EACH_I(REFLECT_EACH, data, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
#define REFLECT_EACH(r, data, i, x) \
PAIR(x); \
template<class Self> \
struct field_data<i, Self> \
{ \
Self & self; \
field_data(Self & self) : self(self) {} \
\
typename make_const<Self, TYPEOF(x)>::type & get() \
{ \
return self.STRIP(x); \
}\
typename boost::add_const<TYPEOF(x)>::type & get() const \
{ \
return self.STRIP(x); \
}\
const char * name() const \
{\
return BOOST_PP_STRINGIZE(STRIP(x)); \
} \
}; \
এটি যা করে তা ধ্রুবক উত্পন্ন করে যা fields_n
ক্লাসে প্রতিফলনযোগ্য ক্ষেত্রগুলির সংখ্যা। তারপরে এটি field_data
প্রতিটি ক্ষেত্রের জন্য বিশেষত্ব দেয় । এটি ক্লাসকেও বন্ধু করে reflector
, এটি ক্ষেত্রগুলিতে ব্যক্তিগত থাকা সত্ত্বেও এটি অ্যাক্সেস করতে পারে:
struct reflector
{
//Get field_data at index N
template<int N, class T>
static typename T::template field_data<N, T> get_field_data(T& x)
{
return typename T::template field_data<N, T>(x);
}
// Get the number of fields
template<class T>
struct fields
{
static const int n = T::fields_n;
};
};
ক্ষেত্রগুলির উপর পুনরাবৃত্তি করতে আমরা দর্শনার্থীর প্যাটার্নটি ব্যবহার করি। আমরা ক্ষেত্রের সংখ্যা থেকে শুরু করে এমপিএল পরিসীমা তৈরি করি এবং সেই সূচীতে ক্ষেত্রের ডেটা অ্যাক্সেস করি। তারপরে এটি ব্যবহারকারী-প্রদত্ত দর্শনার্থীর জন্য ক্ষেত্রের ডেটা প্রেরণ করে:
struct field_visitor
{
template<class C, class Visitor, class I>
void operator()(C& c, Visitor v, I)
{
v(reflector::get_field_data<I::value>(c));
}
};
template<class C, class Visitor>
void visit_each(C & c, Visitor v)
{
typedef boost::mpl::range_c<int,0,reflector::fields<C>::n> range;
boost::mpl::for_each<range>(boost::bind<void>(field_visitor(), boost::ref(c), v, _1));
}
সত্যের মুহুর্তের জন্য আমরা এখন এটি একসাথে রেখেছি। Person
প্রতিবিম্বিত এমন একটি শ্রেণি আমরা এখানে কীভাবে সংজ্ঞায়িত করতে পারি :
struct Person
{
Person(const char *name, int age)
:
name(name),
age(age)
{
}
private:
REFLECTABLE
(
(const char *) name,
(int) age
)
};
print_fields
ক্ষেত্রগুলির উপর পুনরাবৃত্তি করতে প্রতিফলনের ডেটা ব্যবহার করে এখানে একটি সাধারণ ফাংশন দেওয়া হয়েছে:
struct print_visitor
{
template<class FieldData>
void operator()(FieldData f)
{
std::cout << f.name() << "=" << f.get() << std::endl;
}
};
template<class T>
void print_fields(T & x)
{
visit_each(x, print_visitor());
}
print_fields
প্রতিফলনযোগ্য Person
শ্রেণীর সাথে ব্যবহারের একটি উদাহরণ :
int main()
{
Person p("Tom", 82);
print_fields(p);
return 0;
}
কোন ফলাফল:
name=Tom
age=82
এবং ভয়েলা, আমরা 100 টি কোডের নীচে সি ++ এ সবে প্রতিবিম্ব প্রয়োগ করেছি।