【问题标题】:Template and overloads模板和重载
【发布时间】:2018-05-25 02:25:48
【问题描述】:
  template<class Key1, class Key2, class Type> class DualMultimapCache
  {
  public:
     std::list<std::reference_wrapper<Type>> get(Key1 const & key);
     std::list<std::reference_wrapper<Type>> get(Key2 const & key);
     template<class ...Args> Type & put(Key1 const & key, Args const & ...args);
     template<class ...Args> Type & put(Key2 const & key, Args const & ...args);
  };

在这里,我有一个类的公共接口。底层数据结构无关紧要。当Key1Key2 属于不同类型时,一切都会正常工作。如果它们最终是相同的类型,那么重载可能是不可能的。我这样想对吗?

如果我是,有没有办法在保持签名尽可能干净的同时分离重载?

编辑:这里有一个更深入的示例

  template<class Key1, class Key2, class Type> class DualMultimapCache
  {
  public:
     std::list<std::reference_wrapper<Type>> get(Key1 const & key);
     std::list<std::reference_wrapper<Type>> get(Key2 const & key);
     template<class ...Args> Type & put(Key1 const & key, Args const & ...args);
     template<class ...Args> Type & put(Key2 const & key, Args const & ...args);

  private:
     std::unordered_multimap<Key1, std::reference_wrapper<Type>> map_Key1; 
     std::unordered_multimap<Key2, std::reference_wrapper<Type>> map_Key2;
  };

  template<class Key1, class Key2, class Type>
  std::list<std::reference_wrapper<Type>> DualMultimapCache<Key1, Key2, Type>::get(Key1 const & key)
  {
     auto its = map_Key1.equal_range(key);

     if (its.first == map.cend() && its.second == map.cend())
        throw std::out_of_range();
     else
        return { its.first, its.second };
  }

  template<class Key1, class Key2, class Type>
  std::list<std::reference_wrapper<Type>> DualMultimapCache<Key1, Key2, Type>::get(Key2 const & key)
  {
     auto its = map_Key2.equal_range(key);

     if (its.first == map.cend() && its.second == map.cend())
        throw std::out_of_range();
     else
        return { its.first, its.second };
  }

【问题讨论】:

  • 是否允许使用DualMultimapCache&lt;T, T, Foo&gt;?如果没有,只需static_assert(!std::is_same&lt;Key1, Key2&gt;::value, "")
  • get(/put) 使用不同的名称? get_from_key1/get_from_key2 ?
  • @MadScientist 这是我正在使用的案例......事实上,它很可能是标准用例。
  • @Jarod42 这就是我想的解决方案,但是不完成我其他类的相同界面会感觉很奇怪。

标签: c++ templates overloading overload-resolution class-template


【解决方案1】:

您可以为相同键类型的情况部分专门化模板,例如

template <typename Key, typename Type>
class DualMultimapCache<Key, Key, Type>
{
public:
   std::list<std::reference_wrapper<Type>> get(Key const & key);
   template<class ...Args> Type & put(Key const & key, Args const & ...args);
};

【讨论】:

  • 问题是Key 会有不同的含义,并且两者都会重载略有不同的代码路径。
  • @AlexandreParent 那么函数必须以不同的方式命名。当你有完全相同的函数名和签名时,怎么会有人知道它们应该是不同的,更不用说编译器了?
  • 猜对了。只是想看看是否有更好的解决方案。
  • 部分特化的DualMultimapCache&lt;Key, Key, Type&gt;::get 可以采用第二个参数来区分要采用的路径。它可以是无符号或枚举。
【解决方案2】:

我认为你必须使用带有 2 个参数的偏特化,但这并不方便,因为你必须使用稍微不同的接口。为了解决这个问题,我建议使用 SFINAE

template<typename Key1, typename Key2, typename Type,
     typename Enable = void > class DualMultimapCache
{
public:
   std::list<std::reference_wrapper<Type>> get(Key1 const & key);
   std::list<std::reference_wrapper<Type>> get(Key2 const & key);
   template<class ...Args> Type & put(Key1 const & key, Args const & ...args);
   template<class ...Args> Type & put(Key2 const & key, Args const & ...args);
};

template<typename Key1, typename Key2, typename Type > class DualMultimapCache < Key1, Key2, Type,
typename std::enable_if<std::is_same<Key1, Key2>::value>::type >
{
public:
    std::list<std::reference_wrapper<Type>> get(Key1 const & key);
    template<class ...Args> Type & put(Key1 const & key, Args const & ...args);
};

您可以使用具有 3 个模板参数的单一界面,但获得不同的专业化:

DualMultimapCache<int, double, int> t1; // DualMultimapCache template impl
DualMultimapCache<int, int, int> t2;    // DualMultimapCache template 
                                        // specialization impl

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多