Như đã đề cập trong các ý kiến, trước hết hãy nhìn vào BOOST_FUSION_ADAPT_STRUCT
(và bạn bè):
#include <boost/fusion/include/adapt_struct.hpp>
#include <string>
struct Data
{
std::string firstMember;
std::string secondMember;
std::string thirdMember;
};
BOOST_FUSION_ADAPT_STRUCT(
Data,
(std::string, firstMember)
(std::string, secondMember)
(std::string, thirdMember)
)
này biến cấu trúc Data
của bạn thành một chuỗi có thể sử dụng bởi Fusion:
#include <boost/fusion/include/at_c.hpp>
int main()
{
Data d = { "firstData", "secondData", "thirdData" };
std::cout << boost::fusion::at_c<0>(d) << std::endl;
}
này in "firstData"
. Thay đổi chỉ mục để tham khảo các thành viên theo thứ tự.
Hiện tại, chúng tôi có thể tham khảo các thành viên tại thời điểm biên dịch bằng cách sử dụng một số. Nhưng bạn muốn có một cái tên. Cũng lưu ý trong các ý kiến, chuỗi xử lý là một tính năng thời gian chạy ... gần như. C++ 11 cho chúng ta constexpr
.
Đó là một chút khó khăn, nhưng cuối cùng nó trông như thế này:
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/seq.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <stdexcept>
// and repeat for BOOST_FUSION_ADAPT_TPL_STRUCT, etc...
#define REFLECT_STRUCT(NAME, ATTRIBUTES) \
REFLECT_STRUCT_DETAIL(NAME, \
ATTRIBUTES, \
BOOST_PP_SEQ_POP_FRONT( \
BOOST_PP_CAT( \
/* warning: uses fusion implementation details: */ \
BOOST_FUSION_ADAPT_STRUCT_FILLER_0(0,0)ATTRIBUTES, \
_END))) \
#define REFLECT_STRUCT_DETAIL(NAME, ATTRIBUTES, WRAPPEDATTRIBUTES) \
BOOST_FUSION_ADAPT_STRUCT(NAME, ATTRIBUTES) \
\
namespace detail \
{ \
namespace BOOST_PP_CAT(reflect_, NAME) \
{ \
template <int N> \
struct member_name; \
\
BOOST_PP_SEQ_FOR_EACH_I(REFLECT_STRUCT_DETAIL_MEMBER_NAME, \
BOOST_PP_EMPTY, \
WRAPPEDATTRIBUTES) \
\
template <int N> \
constexpr bool member_match_index(const std::size_t index, \
const char* const str, \
const std::size_t len) \
{ \
return index == len || \
(member_name<N>::value()[index] == str[index] \
&& member_match_index<N>(index + 1, str, len)); \
} \
\
template <int N> \
constexpr bool member_match(const char* const str, \
const std::size_t len) \
{ \
return len == member_name<N>::value_length \
&& member_match_index<N>(0, str, len); \
} \
\
constexpr int find_member(const char* const str, \
const std::size_t len) \
{ \
return BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(WRAPPEDATTRIBUTES), \
REFLECT_STRUCT_DETAIL_MEMBER_NAME_TEST, \
BOOST_PP_EMPTY) \
throw std::runtime_error("could not find " \
BOOST_PP_STRINGIZE(NAME) \
" member"); \
} \
} \
} \
\
constexpr int BOOST_PP_CAT(indexof_, NAME)(const char* const str, \
const std::size_t len) \
{ \
return detail::BOOST_PP_CAT(reflect_, NAME)::find_member(str, len); \
} \
\
template <std::size_t N> \
constexpr int BOOST_PP_CAT(indexof_, NAME)(const char (&str)[N]) \
{ \
return detail::BOOST_PP_CAT(reflect_, NAME)::find_member(&str[0], N); \
}
#define REFLECT_STRUCT_DETAIL_EXTRACT_NAME(pair) \
BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(1, pair))
#define REFLECT_STRUCT_DETAIL_MEMBER_NAME(r, data, n, elem) \
REFLECT_STRUCT_DETAIL_MEMBER_NAME_DETAIL(n, REFLECT_STRUCT_DETAIL_EXTRACT_NAME(elem))
#define REFLECT_STRUCT_DETAIL_MEMBER_NAME_DETAIL(n, name) \
template <> \
struct member_name<n> \
{ \
static constexpr std::size_t value_length = sizeof(name); \
typedef const char value_type[value_length]; \
\
static constexpr const value_type& value() \
{ \
return name; \
} \
};
#define REFLECT_STRUCT_DETAIL_MEMBER_NAME_TEST(z, n, text) \
member_match<n>(str, len) ? n :
Có vẻ đáng sợ nhưng có thể đọc được nó nếu bạn dành thời gian để nhặt nó ra xa nhau.
Chúng tôi phải giới thiệu các macro của riêng chúng tôi để cấp quyền truy cập biểu thức liên tục cho tên thành viên; phần lớn xấu xí đến từ việc xử lý danh sách Boost.Preprocessor. Mặc dù Fusion cũng ghi lại tên trong quá trình thích ứng (xem boost::fusion::extension::struct_member_name
), nhưng chúng không được đánh dấu là constexpr
vì vậy không thể sử dụng được với chúng tôi.
Điều này cho phép:
#include <boost/fusion/include/at_c.hpp>
#include <iostream>
#include <string>
struct Data
{
std::string firstMember;
std::string secondMember;
std::string thirdMember;
};
REFLECT_STRUCT(
Data,
(std::string, firstMember)
(std::string, secondMember)
(std::string, thirdMember)
)
// your desired code:
// (note the use of at_c ensures this is evaluated at comple-time)
#define GETMEMBER(data, member) boost::fusion::at_c<indexof_Data(member)>(data)
int main()
{
Data d = { "firstData", "secondData", "thirdData" };
std::cout << boost::fusion::at_c<indexof_Data("firstMember")>(d) << std::endl;
std::cout << GETMEMBER(d, "secondMember") << std::endl;
std::cout << GETMEMBER(d, "thirdMember") << std::endl;
/* causes error: std::cout << GETMEMBER(d, "nonexistent_member") << std::endl; */
}
Mà tôi nghĩ là gần với những gì bạn đang theo đuổi.
Nhưng hãy nhớ rằng điều này có thể không cần thiết: Boost.Fusion có thể đã có những gì bạn cần. Nó sống trong vùng giữa các công cụ biên dịch thuần túy (Boost.MPL) và các công cụ chạy thường xuyên; thích ứng với cấu trúc của bạn và bạn đã có thể làm những việc như lặp lại nó (boost::fusion::for_each
).
Có thể [boost :: fusion] (http://www.boost.org/doc/libs/1_52_0/libs/fusion/doc/html/index.html) có thể trợ giúp ở đây? –
@AlexandreC., Bạn có thể vui lòng cụ thể hơn không? Boost :: fusion là một thư viện lớn :) Ngoài ra, tôi muốn nhắc lại, tôi không muốn có bất kỳ thời gian chạy trên cao, chỉ tính toán thời gian biên dịch. –
@ hate-engine: Xem 'BOOST_FUSION_ADAPT_STRUCT', đó là những gì bạn đang mã hóa một cách hiệu quả. – GManNickG