kfm*_*e04 0 c++ templates type-traits c++11
我有一个简单bi_map的双向映射类的工作代码,用于在两个方向上存储相关的键值对.我目前的用法是,NID某种数字ID或枚举,OBJ而是一个昂贵的不可复制的类对象.
最近,我注意到我也有需要bi_map<NID,std::string>,std::string是一个OBJ应该真正被复制的廉价.
推广下面代码的正确方法是什么,以便用户可以发出信号是否昂贵(我想使用指针/引用)或便宜(我想按值复制所有内容),以便我可以使用正确的实现?
码
template<typename NID,typename OBJ>
class bi_map
{
std::map<NID,OBJ*> m_nid_2_ptr;
std::map<OBJ const*,NID> m_ptr_2_nid;
public:
void insert( NID nid, OBJ& obj )
{
m_nid_2_ptr.insert( std::make_pair( nid, &obj ));
m_ptr_2_nid.insert( std::make_pair( &obj, nid ));
}
NID operator[]( OBJ const& obj ) const
{
return m_ptr_2_nid.at( &obj );
}
OBJ const& operator[]( NID nid ) const
{
return *(m_nid_2_ptr.at( nid ));
}
using pairs_cb = std::function<void(NID,OBJ const&)>;
void pairs( pairs_cb cb ) const
{
for( const auto& p : m_nid_2_ptr )
cb( p.first, *p.second );
}
size_t size() const { return m_nid_2_ptr.size(); }
};
Run Code Online (Sandbox Code Playgroud)
一般来说,有多种选择,我想,没有一个正确的答案.所以,让我们试着找一些适合你的东西.你说你想区分便宜和昂贵的类型.最重要的设计选择是界面.你可以使用:
1)专门用于指针的模板,在使用便宜类型的接口中具有明确的线索:
bi_map< int, std::string* > bi_map_1; // note * is to flag std::string as cheap
bi_map< int, ExpensiveObject > bi_map_2; // no *, thus using heavy implementation
Run Code Online (Sandbox Code Playgroud)
这是这样实现的:
template< typename NID, typename OBJ >
struct bi_map
{
// implementation for expensive objects, use OBJ* or std::shared_ptr<OBJ>
};
// specialize of the second parameter is a pointer
template< typename NID, typename OBJ >
struct bi_map< NID, OBJ* >
{
// implementation for cheap objects, store a copy, i.e., use OBJ
};
Run Code Online (Sandbox Code Playgroud)
当然&,*如果你发现更具可读性,你也可以使用而不是标记类型.
2)如果您不希望在界面中显示廉价/昂贵的分离,即,如果您需要
bi_map< int, std::string > bi_map_1; // no *
bi_map< int, ExpensiveObject > bi_map_2; // no *
Run Code Online (Sandbox Code Playgroud)
你需要不同的东西.一种解决方案是添加默认模板参数:
template< typename >
struct is_expensive_for_bi_map : std::false_type {};
template< typename IND, typename OBJ, bool = is_expensive_for_bi_map< OBJ >::value >
struct bi_map
{
// implementation for expensive objects, use OBJ* or std::shared_ptr<OBJ>
};
template< typename NID, typename OBJ >
struct bi_map< NID, OBJ, false >
{
// implementation for cheap objects, store a copy, i.e., use OBJ
};
Run Code Online (Sandbox Code Playgroud)
对于您认为昂贵的每种类型,您需要添加
template<>
struct is_expensive_for_bi_map< ExpensiveObject > : std::true_type {};
Run Code Online (Sandbox Code Playgroud)
如果昂贵应该是默认值,只需反转名称并调整其余部分,应该很容易.