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

如何在const与非const上下文复用C++类成员辅助函数

如何用单一实现支持const/非const上下文的字典节点访问?

问题描述

我封装了一个std::map的类,提供getter和setter操作值。为了避免重复代码,希望实现一个辅助函数get_private,既能在const对象上调用,也能在非const对象上调用,但不想维护两个重载版本。尝试写模板函数时遇到了模板参数推导失败的错误,同时受Misra/Autosar规则限制不能使用const_cast。

现有代码

class MyTest
{
public:
    void set(const std::string_view &name, const std::string_view &value)
    {
        auto *it = get_private(name);
        if(it != nullptr)
        {
            *it = value;
        }
        else
        {
            m_arr.insert({name, value});
        }
    }

    std::string_view get(const std::string_view &name) const
    {
        auto *it = get_private(name);
        if(it != nullptr)
        {
            return *it;
        }

        return "";
    }

private:
    const std::string_view *get_private(const std::string_view &name) const
    {
        auto it = std::find_if(m_arr.begin(), m_arr.end(), [name](const auto &pair) -> bool {
            return pair.first == name;
        });

        if(it == m_arr.end())
        {
            return nullptr;
        }

        return &(it->second);
    }
    
    std::string_view *get_private(const std::string_view &name)
    {
        auto it = std::find_if(m_arr.begin(), m_arr.end(), [name](const auto &pair) -> bool {
            return pair.first == name;
        });

        if(it == m_arr.end())
        {
            return nullptr;
        }

        return &(it->second);
    }

private:
    std::map<std::string_view, std::string_view> m_arr;
};

使用示例

MyTest mt;
mt.set("name1", "value1");
mt.set("name2", "value3");

std::string_view v = mt.get("name1");
std::cout << v << std::endl;

失败的模板尝试

我曾尝试编写以下模板函数,但编译器报错Candidate template ignored: couldn't infer template argument 'T':

template <typename T>
typename std::conditional<std::is_same<T, std::string_view>::value, std::string_view, const std::string_view>::type
*get_private(const std::string_view &name)
{
}

解决方案

可以通过模板函数复用核心查找逻辑,利用调用上下文的const属性推导返回类型,完全避免const_cast,符合Misra/Autosar规则。以下是两种可行方案:

方案1:基于this类型推导的模板函数

将核心逻辑放在模板函数中,通过std::conditional根据当前对象的const属性决定返回指针类型,外部只需要两个简单的重载触发模板推导:

class MyTest
{
public:
    void set(const std::string_view &name, const std::string_view &value)
    {
        auto *it = get_private(name);
        if(it != nullptr)
        {
            *it = value;
        }
        else
        {
            m_arr.insert({name, value});
        }
    }

    std::string_view get(const std::string_view &name) const
    {
        auto *it = get_private(name);
        if(it != nullptr)
        {
            return *it;
        }

        return "";
    }

private:
    // 模板核心实现:根据Self的const属性决定返回类型
    template <typename Self>
    auto get_private_impl(const std::string_view &name) -> 
        typename std::conditional<std::is_const<Self>::value, 
            const std::string_view*, 
            std::string_view*>::type
    {
        auto it = std::find_if(m_arr.begin(), m_arr.end(), [name](const auto &pair) -> bool {
            return pair.first == name;
        });

        if(it == m_arr.end())
        {
            return nullptr;
        }

        return &(it->second);
    }

    // 非const重载:推导Self为MyTest
    std::string_view* get_private(const std::string_view &name)
    {
        return get_private_impl<MyTest>(name);
    }

    // const重载:推导Self为const MyTest
    const std::string_view* get_private(const std::string_view &name) const
    {
        return get_private_impl<const MyTest>(name);
    }

private:
    std::map<std::string_view, std::string_view> m_arr;
};

方案2:布尔模板参数区分上下文

用布尔模板参数标记是否为const上下文,将核心逻辑封装在模板实现中,外部重载调用对应版本:

class MyTest
{
public:
    void set(const std::string_view &name, const std::string_view &value)
    {
        auto *it = get_private(name);
        if(it != nullptr)
        {
            *it = value;
        }
        else
        {
            m_arr.insert({name, value});
        }
    }

    std::string_view get(const std::string_view &name) const
    {
        auto *it = get_private(name);
        if(it != nullptr)
        {
            return *it;
        }

        return "";
    }

private:
    // 定义类型别名简化返回类型
    template <bool IsConst>
    using ValuePtr = typename std::conditional<IsConst, 
        const std::string_view*, 
        std::string_view*>::type;

    // 模板核心实现:根据IsConst决定map的const属性
    template <bool IsConst>
    ValuePtr<IsConst> get_private_impl(const std::string_view &name) const
    {
        using MapType = typename std::conditional<IsConst, 
            const std::map<std::string_view, std::string_view>, 
            std::map<std::string_view, std::string_view>>::type;
        MapType& map = m_arr;

        auto it = std::find_if(map.begin(), map.end(), [name](const auto &pair) -> bool {
            return pair.first == name;
        });

        if(it == map.end())
        {
            return nullptr;
        }

        return &(it->second);
    }

    // 非const调用:传入false
    std::string_view* get_private(const std::string_view &name)
    {
        return get_private_impl<false>(name);
    }

    // const调用:传入true
    const std::string_view* get_private(const std::string_view &name) const
    {
        return get_private_impl<true>(name);
    }

private:
    std::map<std::string_view, std::string_view> m_arr;
};

方案说明

  • 两种方案都只需要维护一份核心查找逻辑,避免了代码重复。
  • 完全遵守Misra/Autosar规则,未使用const_cast进行类型转换。
  • 编译器会根据调用上下文自动匹配对应的重载,返回正确的const/非const指针。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 07:07:51