C ++ 17 이상에서는 구조를 다음과 같이 변수로 분해 할 수 있습니다.
struct MyStruct
{
int f1;
int f2;
int f3;
};
auto& [f1, f2, f3] = my_struct;
나는 가변 팩 기능에서 그렇게하려고합니다.
template <class ... T, std::size_t...I>
constexpr std::size_t CountFields(std::index_sequence<I...>)
{
T t;
auto& [] = t;
return 0;
}
그러나 변수를 얻기 위해 대괄호 사이의 공간을 채우는 방법을 완전히 모르겠습니다. 최종 목표는 이러한 변수를 사용하여 튜플을 만드는 것입니다 (즉, 튜플 함수에 대한 일반 구조체를 만들려고합니다). 내가 찾은 가장 가까운 것은 this : struct to / from std :: tuple conversion .
하지만 몇 가지 이유로 BOOST를 피해야합니다.
슬프게도 구조화 된 바인딩에서 매개 변수 팩을 사용할 방법이 없다는 것은 분명합니다. 반면에 구조화 된 바인딩 없이는 데이터 멤버를 바인딩 할 수 없습니다.
그러나 데이터 멤버의 양을 제공하면 기존 방식으로 바인딩 할 수 있습니다.
template<size_t>
struct structToTupleHelper;
template<>
struct structToTupleHelper<0>; // ISO C++17 does not allow a decomposition group to be empty.
template<>
struct structToTupleHelper<1>{
template<typename X, size_t... Is>
static auto convert(X&& x, std::index_sequence<Is...>){
auto&& [a1] = std::forward<X>(x); // bound variables are always thought as lvalue.
auto temp = std::forward_as_tuple(a1);
return std::forward_as_tuple(std::get<Is>(temp)...);
}
};
template<>
struct structToTupleHelper<2>{
template<typename X, size_t... Is>
static auto convert(X&& x, std::index_sequence<Is...>){
auto&& [a1, a2] = std::forward<X>(x); // bound variables are always thought as lvalue.
auto temp = std::forward_as_tuple(a1, a2);
return std::forward_as_tuple(std::get<Is>(temp)...);
}
};
// ...
// maybe 16 is enough?
template<typename X, size_t... Is>
auto structToTuple(X&& x, std::index_sequence<Is...> _1){
return structToTupleHelper<sizeof...(Is)>::convert(std::forward<X>(x), _1);
}
template<size_t N, typename X, size_t... Is>
auto structToTuple(X&& x, std::index_sequence<Is...> _1){
return structToTupleHelper<N>::convert(std::forward<X>(x), _1);
}
template<size_t N, typename X>
auto structToTuple(X&& x){
return structToTupleHelper<N>::convert(std::forward<X>(x), std::make_index_sequence<N>());
}
다음과 같이 사용할 수 있습니다.
int ii;
struct A{
int& a;
} a{ii};
struct B{
int a;
} b;
auto t1 = structToTuple<1>(A{ii}); // tuple<int&>, valid.
auto t2 = structToTuple<1>(a); // tuple<int&>, valid.
auto t3 = structToTuple<1>(B{}); // tuple<int&>, invalid: a lvalue reference is bound to a temporary object.
auto t4 = structToTuple<1>(b); // tuple<int&>, valid.
somefunc(structToTuple<1>(B{})); // valid. the temporary object is alive inside 'somefunc'.
structToTuple<1>(A{ii}) = std::tuple(1); // valid. assign 1 to 'ii'.
structToTuple<1>(a) = std::tuple(1); // valid. assign 1 to 'ii'.
structToTuple<1>(B{}) = std::tuple(1); // unexpected. assign 1 to the member of a temporary object.
structToTuple<1>(b) = std::tuple(1); // valid. assign 1 to 'b.a'.
// struct C{
// int a : 8;
// } c;
// auto t5 = structToTuple<1>(C{}); // invalid: bitfields can not be treated as non-const lvalue reference
// auto t6 = structToTuple<1>(c); // invalid: bitfields can not be treated as non-const lvalue reference
전문화하는 것이 번거 롭다고 생각할 수도 있습니다. 다행스럽게도 매크로를 사용하여 단순화 할 수 있습니다. (BOOST가 항상하는 일입니다.)
#define XXX_CONCAT_HELPER(a, b) a##b
#define XXX_CONCAT(a, b) XXX_CONCAT_HELPER(a, b)
#define XXX_COMMA ,
#define XXX_COMMA_FUNC(a) ,
#define XXX_EMPTY
#define XXX_EMPTY_FUNC(a)
#define XXX_REPEAT_0(func, join)
#define XXX_REPEAT_1(func, join) func(1)
#define XXX_REPEAT_2(func, join) XXX_REPEAT_1(func,join) join(2) func(2)
// ...
#define XXX_REPEAT_256(func, join) XXX_REPEAT_255(func,join) join(256) func(256)
#define XXX_REPEAT(func, times, join) XXX_CONCAT(XXX_REPEAT_,times)(func,join)
// macro is not allowed to be recursive, so we need another repeat function.
#define XXX_ALIAS_REPEAT_0(func, join)
#define XXX_ALIAS_REPEAT_1(func, join) func(1)
#define XXX_ALIAS_REPEAT_2(func, join) XXX_ALIAS_REPEAT_1(func,join) join(2) func(2)
// ...
#define XXX_ALIAS_REPEAT_256(func, join) XXX_ALIAS_REPEAT_255(func,join) join(256) func(256)
#define XXX_ALIAS_REPEAT(func, times, join) XXX_CONCAT(XXX_ALIAS_REPEAT_,times)(func,join)
#define STRUCT_TO_TUPLE_TOKEN_FUNC(n) XXX_CONCAT(a,n)
#define STRUCT_TO_TUPLE_FUNC(n) \
template<> \
struct structToTupleHelper<n>{ \
template<typename X, size_t... Is> \
static auto convert(X&& x, std::index_sequence<Is...>){ \
auto&& [XXX_REPEAT(STRUCT_TO_TUPLE_TOKEN_FUNC,n,XXX_COMMA_FUNC)] = std::forward<X>(x); \
auto temp = std::forward_as_tuple(XXX_REPEAT(STRUCT_TO_TUPLE_TOKEN_FUNC,n,XXX_COMMA_FUNC)); \
return std::forward_as_tuple(std::get<Is>(temp)...); \
} \
}; \
XXX_ALIAS_REPEAT(STRUCT_TO_TUPLE_FUNC,128,XXX_EMPTY_FUNC)
#undef STRUCT_TO_TUPLE_TOKEN_FUNC
#undef STRUCT_TO_TUPLE_FUNC
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다