c++ - 如何发出昂贵与廉价模板参数的信号?

标签 c++ templates c++11 typetraits

我有一个简单的工作代码 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(); }
};

最佳答案

一般来说,有多种选择,我想,没有一个正确答案。所以,让我们试着找到适合的东西。你说你想区分便宜的和昂贵的类型。最重要的设计选择是界面。你可以使用:

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

是这样实现的:

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
};

当然,您也可以使用 & 而不是 * 来标记类型,如果您觉得这样更具可读性的话。

2) 如果您希望在界面中显示廉价/昂贵的分离,即,如果您想要

bi_map< int, std::string > bi_map_1; // no *
bi_map< int, ExpensiveObject > bi_map_2; // no *

你需要一些不同的东西。一种解决方案是添加默认模板参数:

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
};

对于您认为昂贵的每种类型,您添加

template<>
struct is_expensive_for_bi_map< ExpensiveObject > : std::true_type {};

如果 expensive 应该是默认值,只需颠倒名称并调整其余部分,应该很容易。

关于c++ - 如何发出昂贵与廉价模板参数的信号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15748343/

相关文章:

c++ - 尝试提供将整数类型 std::vector 除以常量的运算符

c++ - 递归模板解释C++

c++ - 在标准下调用 std::function<void(Args...)> 是否非法?

c++ - C++ 20比较: warning about ambiguous reversed operator

python - 从树莓派上传文件到谷歌驱动器

c++ - 设计用于标记和传输树的 C++ DSL

c++ - 如何调用基于特定派生类的方法

c++ - operator++ 作为后缀和前缀都不适用于 clang

C++别名具有相同名称的类型

c++ - 具有自动返回类型参数推导的可变参数模板