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
相关产品推荐
相关产品推荐

