【问题标题】:Overloading >>operator and initiatializing using an initializer list of custom type重载 >> 运算符并使用自定义类型的初始化列表进行初始化
【发布时间】:2014-01-10 14:54:15
【问题描述】:

我一直在尝试制作一个非常简单的地图容器,我认为能够像这样初始化它会很好:

Hash table = {  "name1" >> value,
                "name2" >> value2,
                "name3" >> value3,
                "name4" >> value4  };

我打算如何解决这个问题是首先制作一个 pair(duo) 数据结构,它将 保留每个元素的名称和值,重载>>运算符以使用名称和值参数返回一个二重奏,并为哈希类创建一个构造函数,通过使用initializer_list构造二重奏元素的向量来初始化它。然后使用二进制搜索方法来检索想要的元素。

不幸的是,我从一开始就碰壁了。 在我开始编写所有代码之前,我想确保正确使用重载,事实上这是一个明智的决定,因为显然它们不是。

这行得通:

#include <iostream>
#include <string>
#include <vector>
#include <initializer_list>

struct duo {
  duo(const std::string key,int value) :key(key) ,value(value) {};
  const std::string key;
  int value;
};

struct Hash {
  std::vector<duo> lister;
  Hash(std::initializer_list<duo> passed) :lister(passed) {};
};

duo operator >> (const std::string& id,int value) {
  return duo(id,value);
}

int main(){
  duo object1("test",1);
  Hash table = {object1};
  std::cout << table.lister[0].key << table.lister[0].value;
}

但这会给出“类型为‘const char [6]’和‘int’的无效操作数给二进制‘operator>>’”

#include <iostream>
#include <string>
#include <vector>
#include <initializer_list>

struct duo {
  duo(const std::string key,int value) :key(key) ,value(value) {};
  const std::string key;
  int value;
};

struct Hash {
  std::vector<duo> lister;
  Hash(std::initializer_list<duo> passed) :lister(passed) {};
    };

duo operator >> (const std::string id,int value) {
  return duo(id,value);
}

int main(){
  Hash table = {"test1" >> 1};
  std::cout << table.lister[0].key << table.lister[0].value;
}

我试图将 std::string 传递给 >> 运算符,因为我不能用原始类型重载。看来这不是一个解决方案。有没有什么方法可以在不将字符串文字显式转换为 std::string 的情况下达到预期的效果?

【问题讨论】:

    标签: c++ map operator-overloading initializer-list


    【解决方案1】:

    显式构造string 将解决此问题:

    int main(){
      Hash table = {std::string("test1") >> 1};
      std::cout << table.lister[0].key << table.lister[0].value;
    }
    

    我也会让&gt;&gt;reference 指向一个 const 字符串,而不是一个值字符串:

    duo operator >> (const std::string& id,int value) {
      return duo(id,value);
    }
    

    您可能认为您可以通过设计以下内容来避免显式构造:

    template <size_t N> duo operator >> (const char (&ary)[N], int id)
    {
      return duo (std::string (ary), id);
    }
    

    ...或:

    duo operator >> (const char* id, int value)
    {
      return duo (std::string (id), value);
    }
    

    但是你不能因为 C++ 不允许为指针(或任何原始)类型覆盖 operator &gt;&gt;。如果你尝试这个,你会得到一个编译器错误,类似于“必须有一个类或枚举类型的参数”。为了提供运算符重载,您必须提供至少一个类或枚举类型的参数。


    所以让我们考虑一下。我们不能将operator&lt;&lt; 与两个原始参数一起使用,因为这是不允许的。您真正要寻找的是没有任何显式初始化的干净初始化语法。唯一真正阻碍我们的是初始化。那么,如果我们尝试构建一个实际上使用 两个 运算符但看起来仍然干净的东西怎么办?如果我们尝试构建类似的东西会怎样:

    Hash table = {"test1" <MapTo> 1};
    

    这不是完全您想要的语法,但它相当接近。所以让我们尝试构建这个:

    这里有两个运算符:operator&lt;operator&gt;operator&lt; 的参数是字符串文字 "test1 和一些名为 MapTo 的对象。 operator&gt; 的参数是 operator&lt; 返回的任何内容和整数文字 1

    先看operator&lt;,我们来做一个原型:

    template <size_t N> std::string operator < (const char (&ary)[N], Something op)
    

    我们知道我们希望operator&gt; 返回一个duo,那么Something 需要是什么来促进它呢?我们真正需要operator&lt; 做的就是将字符串文字转换为std::string,所以让我们尝试一下:

    class HashOperation
    {
    public:
      template <size_t N> std::string cvt (const char (&ary)[N]) const
      {
        return std::string (ary);
      }
    } MapTo;
    
    
    template <size_t N> std::string operator < (const char (&ary)[N], HashOperation op) 
    {
      return op.cvt (ary);
    }
    

    现在我们有了std::string,让我们用它和int一起构建一个duo

    duo operator> (const std::string& key, int value)
    {
      return duo (key, value);
    }
    

    这很容易。让我们把它们放在一起(Live Demo):

    #include <iostream>
    #include <string>
    #include <vector>
    #include <initializer_list>
    
    struct duo {
      duo(const std::string key,int value) :key(key) ,value(value) {};
      template <size_t N> duo (const char (&ary)[N], int value) : key (ary), value (value) {};
      const std::string key;
      int value;
    };
    
    struct Hash {
      std::vector<duo> lister;
      Hash(std::initializer_list<duo> passed) :lister(passed) {};
        };
    
    
    class HashOperation
    {
    public:
      template <size_t N> std::string cvt (const char (&ary)[N]) const
      {
        return std::string (ary);
      }
    } MapTo;
    
    
    template <size_t N> std::string operator < (const char (&ary)[N], HashOperation op)
    {
      return op.cvt (ary);
    }
    
    duo operator> (const std::string& key, int value)
    {
      return duo (key, value);
    }
    
    int main(){
      Hash table =
      {
        "test1" <MapTo> 1,
        "test2" <MapTo> 2
      };
    
      std::cout << table.lister[0].key << table.lister[0].value;
    }
    

    【讨论】:

    • 我知道显式转换可以解决问题。不过我想知道达到预期的效果。
    • @JohnDibling 对不起。
    • template &lt;size_t N&gt; 是干什么用的?
    • @Veritas:请参阅我的下一个编辑。我可能已经找到了接近你想要的东西。
    • @Siidheesh:这允许传递一个 char 字面量数组而不会降级为指针,从而保持数组的大小不变。回想起来,这里并不是绝对必要的。
    【解决方案2】:

    对于两种基本类型char const *int,您是trying to 重载operator&gt;&gt;;这是not allowed 的语言。要使其以当前形式工作,您需要从第一个参数显式创建 std::string

    Hash table = {std::string("test1") >> 1};
    

    当然,另一种选择是放弃这种初始化语法,并坚持使用逗号分隔的对。

    #include <iostream>
    #include <string>
    #include <vector>
    #include <initializer_list>
    #include <utility>
    
    using duo = std::pair<std::string, int>;
    
    struct Hash {
      std::vector<duo> lister;
      Hash(std::initializer_list<duo> passed) :lister(passed) {};
    };
    
    int main(){
      Hash table = {{"test1", 1}, {"test2", 2}};
      std::cout << table.lister[0].first << table.lister[0].second;
    }
    

    【讨论】:

    • 有什么方法可以在不显式转换为std::string的情况下达到想要的效果?
    • @Veritas 我添加了一个替代解决方案,但它不使用您的operator&gt;&gt;。我不知道在没有明确构造字符串的情况下使该运算符工作的任何方法。
    • 这就是我所担心的。我可以找到很多替代方案,但我将不得不抛弃那种干净的初始化外观。
    【解决方案3】:

    您为 std::string 和 int 定义了 operator>>,但您尝试将其与参数 const char[] 和 int 一起使用。你需要让编译器知道第一个参数是std::string。尝试 {"test1"s &gt;&gt; 1}

    【讨论】:

    • 这是标准的 c++ 吗? gcc 不会接受它,我在我的参考文献中找不到它。
    • 不,不是,所以要么明确地说 std::string("test1") 要么定义 s 或 _s 后缀。
    猜你喜欢
    • 2012-03-11
    • 2015-04-24
    • 2016-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-31
    相关资源
    最近更新 更多