如何在C++17之前版本中实现propagation_const?
在C++17之前实现const传播的propagation_const
在你的代码中,const A对象调用bar()时,成员b_是const std::shared_ptr<B>——但shared_ptr的const仅限制指针本身不能被重新赋值,不会影响它指向的对象的const属性,因此b_->foo()会调用非const版本的foo()。要实现const传播(即宿主对象是const时,通过内部指针访问到的对象也被视为const),我们可以手动实现一个propagation_const模板类,在C++17之前模拟这一行为。
实现思路
核心是通过重载const和非const版本的operator->、operator*以及get()方法,根据当前propagation_const对象的const属性,返回对应限定类型的指针/引用:
- 当对象是非const时,直接返回内部指针的原生访问结果;
- 当对象是const时,返回指向
const元素的指针/引用,强制后续成员函数调用匹配const版本。
完整实现代码
#include <iostream> #include <memory> #include <type_traits> template <typename T> class propagation_const { public: // 转发构造参数给内部指针 template <typename... Args> propagation_const(Args&&... args) : ptr_(std::forward<Args>(args)...) {} // 非const版本:返回原生指针 typename std::pointer_traits<T>::pointer operator->() { return ptr_.operator->(); } // const版本:返回指向const元素的指针 typename std::add_const<typename std::pointer_traits<T>::element_type>::type* operator->() const { return ptr_.operator->(); } // 非const版本:返回原生引用 typename std::pointer_traits<T>::reference operator*() { return *ptr_; } // const版本:返回const元素的引用 typename std::add_const<typename std::pointer_traits<T>::element_type>::type& operator*() const { return *ptr_; } // 获取内部指针的非const版本 typename std::pointer_traits<T>::pointer get() { return ptr_.get(); } // 获取内部指针的const版本 typename std::add_const<typename std::pointer_traits<T>::element_type>::type* get() const { return ptr_.get(); } private: T ptr_; }; class B { public: void foo() const { std::cout << "foo const" << std::endl; } void foo() { std::cout << "foo non-const" << std::endl; } }; class A { public: void bar() const { std::cout << "bar const" << std::endl; b_->foo(); // 此时b_->是const B*,调用const版本foo } void bar() { std::cout << "bar non-const" << std::endl; b_->foo(); // 此时b_->是B*,调用非const版本foo } propagation_const<std::shared_ptr<B>> b_{std::make_shared<B>()}; }; int main() { const A a; a.bar(); // 输出:bar const\nfoo const A a_nonconst; a_nonconst.bar(); // 输出:bar non-const\nfoo non-const }
效果说明
- 当使用
const A对象调用bar()时,b_作为const成员,其operator->返回const B*,因此会触发B::foo() const; - 当使用非const
A对象时,operator->返回B*,正常调用非const版本的foo()。
这个实现兼容常见的智能指针(如std::shared_ptr、std::unique_ptr)和原始指针,满足C++17之前的标准要求。
内容的提问来源于stack exchange,提问作者getsoubl
相关产品推荐
相关产品推荐

