如何批量提升类模板成员函数至外层trait_vector类模板?
通用成员函数提升方案
核心思路
我们可以实现一个通用的成员函数提升模板,将单个元素的成员函数映射到trait_vector容器上,避免为每个成员函数重复编写遍历逻辑。同时这个方案可以轻松扩展到其他类类型。
实现步骤
1. 完善two_val类
添加所需的成员函数,并确保它们是const(遍历容器时通常访问const元素):
template<class T> class two_val{ private: T first_val; T second_val; public: using type = T; two_val() : first_val {}, second_val {} {} two_val(T f, T s) : first_val{f}, second_val{s} {} // 方便测试的构造函数 T get_first() const { return first_val; } T get_second() const { return second_val; } T add_first_and_second() const { return first_val + second_val; } bool check_equality_of_first_and_second() const { return first_val == second_val; } };
2. 实现trait_vector的通用lift成员模板
在trait_vector中添加一个模板成员函数,接收成员函数指针作为模板参数,自动推导返回类型并生成对应的容器操作:
#include <vector> #include <functional> #include <type_traits> template <typename T> struct is_two_val : std::false_type {}; template <typename T> struct is_two_val<two_val<T>> : std::true_type {}; template<class T> class trait_vector{ private: std::vector<T> vec; public: trait_vector() : vec {} {} void push_back(const T& elem) { vec.push_back(elem); } void reserve(std::size_t n) { vec.reserve(n); } // 通用提升模板:接收成员函数指针,返回对应类型的trait_vector template <auto MemFunc> auto lift() requires (is_two_val<T>::value) { // 推导成员函数调用后的返回类型 using ResultType = std::invoke_result_t<decltype(MemFunc), const T&>; trait_vector<ResultType> result; result.reserve(vec.size()); // 遍历容器,对每个元素调用成员函数并收集结果 for (const auto& elem : vec) { result.vec.push_back(std::invoke(MemFunc, elem)); } return result; } // 为常用成员函数封装直接调用接口(可选,提升可读性) auto get_first() requires (is_two_val<T>::value) { return lift<&T::get_first>(); } auto get_second() requires (is_two_val<T>::value) { return lift<&T::get_second>(); } auto add_first_and_second() requires (is_two_val<T>::value) { return lift<&T::add_first_and_second>(); } auto check_equality_of_first_and_second() requires (is_two_val<T>::value) { return lift<&T::check_equality_of_first_and_second>(); } };
3. 扩展到其他类的通用方案
如果后续需要从其他模板类向trait_vector提升成员函数,只需要:
- 定义对应的类型判断
trait(比如is_three_val) - 修改
lift函数的约束条件,或者用C++20的概念统一约束:
也可以直接去掉约束,让// 定义概念:判断类型是否是可提升的容器元素 template <typename T> concept LiftableElement = is_two_val<T>::value || is_three_val<T>::value; // 修改lift的约束 template <auto MemFunc> auto lift() requires (LiftableElement<T>) { // 实现逻辑不变 }std::invoke自动处理(只要传入的成员函数对T有效即可)。
测试示例
#include <iostream> int main() { trait_vector<two_val<int>> vec; vec.push_back(two_val<int>{1, 2}); vec.push_back(two_val<int>{3, 3}); vec.push_back(two_val<int>{5, 7}); // 调用封装好的成员函数 auto firsts = vec.get_first(); for (const auto& val : firsts.vec) std::cout << val << " "; // 输出1 3 5 std::cout << "\n"; auto equals = vec.check_equality_of_first_and_second(); for (const auto& val : equals.vec) std::cout << val << " "; // 输出0 1 0 std::cout << "\n"; // 直接用lift调用任意成员函数 auto sums = vec.lift<&two_val<int>::add_first_and_second>(); for (const auto& val : sums.vec) std::cout << val << " "; // 输出3 6 12 std::cout << "\n"; return 0; }
这个方案的优势在于:
- 只需编写一次遍历逻辑,所有成员函数复用同一模板
- 可轻松扩展到其他类类型,只需添加对应的类型判断或概念约束
- 既可以通过封装的成员函数(如
get_first)调用,也可以直接用lift模板调用任意成员函数
内容的提问来源于stack exchange,提问作者Manuel Du
相关产品推荐
相关产品推荐

