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

如何实现获取类中任意std::vector元素的通用索引访问函数?

问题描述

现有一个仅以各类std::vector作为数据成员的类S,希望实现一个通用函数,通过索引获取任意vector中的元素。我尝试用getter指针实现了功能,但觉得可读性不足,附上类S的示例代码和我的实现,寻求更优方案。

类S示例代码

class S
{
private:
    std::vector<int> someIntegers;
    std::vector<double> someDoubles;
    std::vector<double> someDoubles2;
    std::vector<int> someIntegers2;
    std::vector<B> someBs;
public:
    const std::vector<int>& getSomeIntegers() const { return someIntegers; }
    const std::vector<double>& getSomeDoubles() const { return someDoubles; }
    const std::vector<double>& getSomeDoubles2() const { return someDoubles2; }
    const std::vector<int>& getSomeIntegers2() const { return someIntegers2; }
    const std::vector<B>& getSomeBs() const { return someBs; }
    // 其他getter...
};

我的实现代码

template<typename T>
std::optional<T> getByIndex(const S& s, const std::vector<T>& (S::*getCnt)() const, size_t index = 0)
{
    if (const auto& cnt = (s.*getCnt)();
        index >= 0 && index < cnt.size())
        return cnt.at(index);
    return {};
}
优化方案

方案1:枚举+重载函数,提升可读性

定义枚举标识不同vector成员,针对每个枚举值重载getByIndex,调用对应getter:

enum class VectorType {
    Integers,
    Doubles,
    Doubles2,
    Integers2,
    Bs
};

std::optional<int> getByIndex(const S& s, VectorType type, size_t index = 0) {
    switch(type) {
        case VectorType::Integers: {
            const auto& vec = s.getSomeIntegers();
            return index < vec.size() ? std::optional<int>(vec.at(index)) : std::nullopt;
        }
        case VectorType::Integers2: {
            const auto& vec = s.getSomeIntegers2();
            return index < vec.size() ? std::optional<int>(vec.at(index)) : std::nullopt;
        }
        default: return std::nullopt;
    }
}

std::optional<double> getByIndex(const S& s, VectorType type, size_t index = 0) {
    switch(type) {
        case VectorType::Doubles: {
            const auto& vec = s.getSomeDoubles();
            return index < vec.size() ? std::optional<double>(vec.at(index)) : std::nullopt;
        }
        case VectorType::Doubles2: {
            const auto& vec = s.getSomeDoubles2();
            return index < vec.size() ? std::optional<double>(vec.at(index)) : std::nullopt;
        }
        default: return std::nullopt;
    }
}

std::optional<B> getByIndex(const S& s, VectorType type, size_t index = 0) {
    if (type == VectorType::Bs) {
        const auto& vec = s.getSomeBs();
        return index < vec.size() ? std::optional<B>(vec.at(index)) : std::nullopt;
    }
    return std::nullopt;
}

调用示例:

auto val = getByIndex(s, VectorType::Integers, 2);

方案2:标签类封装类型信息

定义对应每个vector的标签类,通过模板特化实现函数:

struct IntegersTag {};
struct DoublesTag {};
struct Doubles2Tag {};
struct Integers2Tag {};
struct BsTag {};

template<typename Tag>
std::optional<typename std::invoke_result_t<decltype(&S::getSomeIntegers), const S&>::value_type>
getByIndex(const S& s, Tag, size_t index = 0);

template<>
std::optional<int> getByIndex(const S& s, IntegersTag, size_t index) {
    const auto& vec = s.getSomeIntegers();
    return index < vec.size() ? std::optional<int>(vec.at(index)) : std::nullopt;
}

template<>
std::optional<double> getByIndex(const S& s, DoublesTag, size_t index) {
    const auto& vec = s.getSomeDoubles();
    return index < vec.size() ? std::optional<double>(vec.at(index)) : std::nullopt;
}

// 其他标签的特化实现...

调用示例:

auto val = getByIndex(s, IntegersTag{}, 1);

方案3:lambda封装getter,简化调用

用lambda包装getter,让调用意图更清晰,无需修改原有类:

template<typename Getter, typename T = typename std::invoke_result_t<Getter, const S&>::value_type>
std::optional<T> getByIndex(const S& s, Getter getter, size_t index = 0) {
    const auto& vec = getter(s);
    return index < vec.size() ? std::optional<T>(vec.at(index)) : std::nullopt;
}

调用示例:

auto val = getByIndex(s, [](const S& s) { return s.getSomeDoubles(); }, 3);

方案4:作为类S的成员函数

若允许修改类S,将通用函数作为成员函数,结合模板或重载:

class S {
    // 原有私有成员...
public:
    // 原有getter...

    template<typename T>
    std::optional<T> getByIndex(const std::vector<T>& (S::*getter)() const, size_t index = 0) const {
        const auto& vec = (this->*getter)();
        return index < vec.size() ? std::optional<T>(vec.at(index)) : std::nullopt;
    }

    // 可选:结合枚举的重载版本
    enum class VectorType { Integers, Doubles, Doubles2, Integers2, Bs };
    std::optional<int> getByIndex(VectorType type, size_t index = 0) const {
        switch(type) {
            case VectorType::Integers: {
                const auto& vec = getSomeIntegers();
                return index < vec.size() ? std::optional<int>(vec.at(index)) : std::nullopt;
            }
            case VectorType::Integers2: {
                const auto& vec = getSomeIntegers2();
                return index < vec.size() ? std::optional<int>(vec.at(index)) : std::nullopt;
            }
            default: return std::nullopt;
        }
    }
};

调用示例:

S s;
auto val = s.getByIndex(&S::getSomeIntegers, 0);
// 或者用枚举版本
auto val2 = s.getByIndex(S::VectorType::Doubles, 1);

内容的提问来源于stack exchange,提问作者SteveJ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 02:20:39