You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何批量提升类模板成员函数至外层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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 04:52:07