代码之家  ›  专栏  ›  技术社区  ›  Hani Gotc

具有不同结构的模板映射的设计问题

  •  1
  • Hani Gotc  · 技术社区  · 6 年前

    问题描述和问题

    我有一个 template Class1 . 它包含在 map 我想在其中插入结构 A B .

    问题是这些建筑 一个 具有不同类型的成员变量。结构 一个 有一个 std::string 成员变量而结构 有一个 int 成员变量。

    比较器基于结构 一个 . 所以很明显,当我想插入一个结构B时,它不会编译。

    Class1<B,B> c2;
    c2.AddElement({1},{1});
    

    如何解决设计问题?例如,是否有可能 一级 作为 模板 上课做点什么 TestCompare 是吗?

    我也有限制。 我不能修改结构 一个 是的。它们是用C代码编写的我无权更改它们,因为它们是其他用户使用的外部代码我只是尽可能地简化了代码。


    源代码

    代码是在 cpp.sh

    #include <iostream>
    #include <string>
    #include <map>
    
    typedef struct {
        std::string a;
    } A;
    
    typedef struct {
        int b;
    } B;
    
    
    template<typename T1, typename T2> class Class1 {
        public :
          struct TestCompare {
             bool operator()(const T1 & lhs, const T1 & rhs) const {
            return lhs.a < rhs.a;
             }
           };
           Class1() {}
           ~Class1() {}
           void AddElement(const T1 & key, const T2 & value) {
              m.emplace(key, value);
            }
        private :
         std::map<T1,T2,TestCompare> m;
    };
    
    int main()
    {
      Class1<A,A> c1;
      c1.AddElement({"1"},{"1"});
    
      // Problem here. Obviously it will not compile because the Operator is using 
      // the member variable of struct A.
      //Class1<B,B> c2;
      //c2.AddElement({1},{1});
      //return 0;
    }
    

    新源代码

     // Example program
    #include <iostream>
    #include <string>
    #include <map>
    
    typedef struct {
        std::string a;
    } A;
    
    typedef struct {
        int b;
    } B;
    
    
    bool operator<(const A & lhs, const A & rhs) {
        return lhs.a < rhs.a;
    }
    
    bool operator<(const B & lhs, const B & rhs) {
        return lhs.b < rhs.b;
    }
    
    template<typename T1, typename T2> class Class1 {
        public :
        Class1() {}
        ~Class1() {}
        void AddElement(const T1 & key, const T2 value) {
            m.emplace(key, value);
        }
    
         std::map<T1,T2> getMap() {
            return m;
        }
    
        private :
         std::map<T1,T2> m;
    };
    
    int main()
    {
      Class1<A,A> c1;
      c1.AddElement({"1"},{"1"});
    
      // Problem here. Obviously it will not compile because the Operator is using 
      // the member variable of struct A.
      Class1<B,B> c2;
      c2.AddElement({1},{1});
      c2.AddElement({2},{2});
    
      for(const auto &e: c2.getMap()) {
          std::cout << e.first.b << " " << e.first.b << std::endl;
      }
      return 0;
    }
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   john    6 年前

    我想你可以搬走 TestCompare Class1 和模板。

    template<typename T> struct TestCompare {
        bool operator()(const T & lhs, const T & rhs) const {
            // default implementation
            return lhs < rhs;
        }
    };
    
    template<typename T1, typename T2> class Class1 {
         ...
        private :
         std::map<T1,T2,TestCompare<T1>> m;
    }
    

    然后你可以专攻 测试比较 对于 A B

    template<> struct TestCompare<A> {
        bool operator()(const A & lhs, const A & rhs) const {
            return lhs.a < rhs.a;
        }
    };
    
    template<> struct TestCompare<B> {
        bool operator()(const B & lhs, const B & rhs) const {
            return lhs.b < rhs.b;
        }
    };
    

    编辑: 实际上你可以用 std::less 而不是 测试比较 是的。差不多是一样的,而且 std::map 使用 标准::更少 默认情况下。

        2
  •  1
  •   An0num0us parreirat    6 年前

    TestCompare 要求您使用的每种类型都必须有一个成员 a 可以用 < . 这是很多要求,这意味着一个可怕的设计添加第三个模板参数,用于传递比较对象的函数或函子

    struct CompareA {
        bool operator()(A const & lhs, A const & rhs) const {
            return lhs.a < rhs.a;
        }
    };
    
    struct CompareB {
       bool operator()(B const& lhs, B const& rhs) const {
           /*...*/
       }
    };
    
    template<typename KeyT, typename ValueT, typename Compare> class Dict {
        public :
           Class1() {}
           ~Class1() {}
           void AddElement(KeyT const & key, ValueT const & value) {
              m.emplace(key, value);
           }
        private :
           std::map<KeyT, ValueT, Compare> m;
    };
    
    Dict<A, B, CompareA> dictA;
    Dict<B, B CompareB> dictB;
    

    你可以专门化结构 测试比较 ,就像john在他的答案中建议的那样,并将其作为默认模板参数提供

    template<typename KeyT, typename ValueT, typename Compare = TestCompare<KeyT>> class Dict { /*...*/ };
    

    这样的解决方案只允许您提供两个参数,如下所示

    Dict<B, B> dict;
    

    同时仍然保持在必要时提供另一个比较器的能力。