C++11中避免模板特化冗余的惯用实现方案
实现支持普通类型与指针类型的
Box<T>结构体 我正在实现一个用于处理数据的结构体Box<T>,它既可以存储普通类型,也可以存储指针类型——Box<int>和Box<int*>都是合法的。核心需求是:当Box拥有data的所有权时,如果存储的是指针类型,就需要在析构时调用delete释放数据。
初始C++11解决方案
一开始我想到了这样的实现方式:
template <typename T> struct BoxTraits; template <typename T> struct Box { using traits_t = BoxTraits<T>; T data; ~Box() = default; // 我知道这不是必须的 T get_data() { return traits_t::get_data(this); } }; template <typename T> struct Box<T*> { using traits_t = BoxTraits<T*>; T* data; ~Box() { delete data; } T* get_data() { return traits_t::get_data(this); } }; template <typename T> struct BoxTraits { static T get_data(Box<T>* const box) { return box->data; } };
方案问题分析
这个实现的问题非常明显:每给Box新增一个成员方法,都要在每个特化版本里重复编写样板代码;而且如果要支持Box<T*const>,还得再写一个对应的特化版本,维护起来成本极高。
在C14及以后的版本里,我们可以用if constexpr结合is_ptr<T> trait,只在需要特殊处理的方法里写差异化逻辑,但我想知道,有没有办法在C11中实现类似的简洁效果?
更简洁的改进方案(支持Box<U*const>)
后来我想到了这个更简短的实现:
template <typename T> struct is_ptr { static const bool value = false; }; template <typename U> struct is_ptr<U*> { static const bool value = true; }; template <typename U> struct is_ptr<U*const> { static const bool value = true; }; template <typename T> struct Box { T data; ~Box() { if constexpr (is_ptr<T>::value) { delete data; } } T get_data() { return data; } };
需要注意的是,if constexpr是C17才引入的特性,所以这个方案其实无法直接在C11中编译运行。如果要适配C++11,需要借助SFINAE(替换失败并非错误)或者标签分发的方式来实现条件分支逻辑。
内容的提问来源于stack exchange,提问作者doliphin
相关产品推荐
相关产品推荐

