自动从任何类型的两个元组==>成对的元组转换

问题描述 投票:0回答:1

我想要 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++ reflection c++17
1个回答
0
投票

您可以创建一个合并函数,将任意类型但具有相同数量对象的两个元组合并,如下所示:

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)>());
}

演示 C++20

如果您想合并没有引用的元组,则只需提供第二个重载,其中函数的参数从

std::tuple<Args&...>
更改为
std::tuple<Args...>

© www.soinside.com 2019 - 2024. All rights reserved.