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

C++17中如何修改BaseContainer以支持传递const std::vector容器?

问题描述

我希望在代码中传递const变量,且不使用指针。可以通过std::any并重载->运算符规避指针,但无法将生成的任意对象的vector作为const变量传递——取消代码第49行的#define CONST注释后,代码无法编译。请问如何修改BaseContainer的定义,以支持传递const对象的vector?

原代码

#include <any>
#include <vector>

// 代码灵感来源:https://www.fluentcpp.com/2021/01/29/inheritance-without-pointers/ 
// 需要C++17编译

template<typename Base>
struct BaseContainer
{
public:
    template<typename ConcreteType>
    BaseContainer(ConcreteType&& object)
        : storage{std::forward<ConcreteType>(object)}
        , getter{ [](std::any &storage) -> Base& { return std::any_cast<ConcreteType&>(storage); } }
    {}
    
    Base *operator->() { return &getter(storage); }
    
private:
    std::any storage;
    Base& (*getter)(std::any&);
};

class Entry
{
public:
    Entry() {};
    
    Entry *self() { return this; }
    
    void print()
    {
        printf("2\n");
    }
};

class Inherited : public Entry
{
public:
    Inherited() {}
    
    void koko()
    {
        printf("3\n");
    }
};

// #define CONST
void printThem(
#ifdef CONST
               const
#endif
               std::vector<BaseContainer<Entry>> &entries)
{
    size_t i = 0;
    for (auto &e : entries)
    {
        e->print();
        if (i > 0)
        {
            auto f = static_cast<Inherited *>(e->self());
            f->koko();
        }
        i++;
    }
}

int main(int argc, char *argv[])
{
    std::vector<BaseContainer<Entry>> entries;
    entries.push_back(Entry{});
    entries.push_back(Inherited{});
    printThem(entries);
}

编译与运行命令

# 编译
c++ --std=c++17 jkl.cpp
# 运行
./a.out

预期输出

2
2
3

解决方案

要支持const容器,核心是给BaseContainer补充const版本的成员函数,因为const对象只能调用const成员,且无法修改内部存储。具体修改如下:

1. 修改BaseContainer结构

添加const版本的operator->和对应的const getter函数指针:

template<typename Base>
struct BaseContainer
{
public:
    template<typename ConcreteType>
    BaseContainer(ConcreteType&& object)
        : storage{std::forward<ConcreteType>(object)}
        , getter{ [](std::any &storage) -> Base& { return std::any_cast<ConcreteType&>(storage); } }
        // 新增const版本的getter
        , const_getter{ [](const std::any &storage) -> const Base& { return std::any_cast<const ConcreteType&>(storage); } }
    {}
    
    Base *operator->() { return &getter(storage); }
    // 新增const版本的->运算符
    const Base *operator->() const { return &const_getter(storage); }
    
private:
    std::any storage;
    Base& (*getter)(std::any&);
    // 新增const版本的getter函数指针
    const Base& (*const_getter)(const std::any&);
};

2. 补充const版本的成员函数

原Entry和Inherited的成员函数需要补充const版本,确保在const上下文中可调用:

class Entry
{
public:
    Entry() {};
    
    Entry *self() { return this; }
    // 新增const版本的self()
    const Entry *self() const { return this; }
    
    // 将print()改为const成员函数(不修改对象状态的函数都应该设为const)
    void print() const
    {
        printf("2\n");
    }
};

class Inherited : public Entry
{
public:
    Inherited() {}
    
    // 将koko()改为const成员函数
    void koko() const
    {
        printf("3\n");
    }
};

3. 调整printThem函数的循环逻辑

在const容器中,循环变量需要是const引用,且static_cast要匹配const指针:

void printThem(
#ifdef CONST
               const
#endif
               std::vector<BaseContainer<Entry>> &entries)
{
    size_t i = 0;
    // 改为const auto& e
    for (const auto &e : entries)
    {
        e->print();
        if (i > 0)
        {
            // 转换为const Inherited*
            auto f = static_cast<const Inherited *>(e->self());
            f->koko();
        }
        i++;
    }
}

完成以上修改后,打开#define CONST注释,代码即可正常编译并输出预期结果。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:27:01