我想要 C++17 中的某种反射。
为了测试其功能和限制,我创建了一个仅复制 int 和 float 的自定义复制构造函数。
但是,我不知道如何自动合并元组。
通过使用
getAllFields()
的力量,请仅在“vvv”部分编辑代码以使其自动。
MCVE :: https://coliru.stacked-crooked.com/a/457e91d9a0469be8
class B{public:
int c1;
std::string c2;
float c3;
constexpr auto getAllFields() {
return std::tie(c1, c2, c3);
}
static auto getAllFields_pair(B& b1, B& b2) {
///vvv insert your code here
// but please don't call c1/c2/c3 by variable names directly
return std::tuple<
std::tuple<int&,int&>
,std::tuple<std::string&, std::string&>
,std::tuple<float&,float&> >{
std::tuple<int&,int&>{b1.c1,b2.c1}
,std::tuple< std::string&, std::string&>{b1.c2,b2.c2}
,std::tuple<float&,float&>{b1.c3,b2.c3}
};
///^^^ edit (only) here
}
我是这样称呼它的::-
static void copyIntAndFloatToB2(B& b1, B& b2) {
auto f=[](auto& b1_cx,auto& b2_cx){
using typee=std::remove_reference_t<decltype(b1_cx)>;
if constexpr(std::is_same_v<typee,int> || std::is_same_v<typee,float>){
b2_cx= b1_cx;
}
};
std::apply(
[&f](auto&&... aField) {
(
f(std::get<0>(aField),std::get<1>(aField))
, ...);
},
getAllFields_pair(b1,b2)
);
}
};
这是它的用法::-
int main(){
B b1;
B b2;
b1.c1=5;
B::copyIntAndFloatToB2(b1,b2);
std::cout<<b2.c1<<std::endl; ///: print 5
}
我对
std::tie
和std::apply
很陌生。
上面的代码是从自动生成方法调用扩展到类的每个成员对象
您可以创建一个合并函数,将任意类型但具有相同数量对象的两个元组合并,如下所示:
C++17
namespace detail {
template<typename... Args1, typename... Args2, std::size_t ... Is>
auto merge_tuples(std::tuple<Args1&...> t1, std::tuple<Args2&...> t2,
std::index_sequence<Is...>) {
return std::make_tuple(std::tie(std::get<Is>(t1), std::get<Is>(t2))...);
}
}
template<typename... Args1, typename... Args2>
auto merge_tuples(std::tuple<Args1&...> t1, std::tuple<Args2&...> t2) {
static_assert(sizeof...(Args1) == sizeof...(Args2));
return detail::merge_tuples(t1, t2, std::make_index_sequence<sizeof...(Args1)>());
}
演示 C++17 然后你可以用
替换你的代码return merge_tuples(b1.getAllFields(), b2.getAllFields());
C++20 引入了约束和模板化 lambda,允许使用以下更好的函数,其中
static_assert
被 requires
替换,并且单独的函数可以被模板化 lambda 替换。
template<typename... Args1, typename... Args2>
requires (sizeof...(Args1) == sizeof...(Args2))
auto merge_tuples(std::tuple<Args1&...> t1, std::tuple<Args2&...> t2) {
return [&]<std::size_t ... Is>(std::index_sequence<Is...>) {
return std::make_tuple(std::tie(std::get<Is>(t1), std::get<Is>(t2))...);
}(std::make_index_sequence<sizeof...(Args1)>());
}
如果您想合并没有引用的元组,则只需提供第二个重载,其中函数的参数从
std::tuple<Args&...>
更改为 std::tuple<Args...>
。