重载>>运算符并使用自定义类型的初始值设定项列表启动

Overloading >>operator and initiatializing using an initializer list of custom type

本文关键字:gt 列表 启动 类型 运算符 重载 自定义      更新时间:2023-10-16

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

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

我打算如何做到这一点,首先制作一对(双人)数据结构保留每个元素的名称和值,重载>>运算符以使用名称和值参数返回一个duo,并为hash类创建一个构造函数来初始化它,方法是使用initializer_list来构造duo元素的向量。然后使用二进制搜索方法来检索所需的元素。

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

这项工作:

#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类型的无效操作数赋予二进制运算符>>">

#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的情况下实现所需的效果?

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

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

我也会让>>对常量字符串进行引用,而不是按值的字符串:

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 >>。如果您尝试此操作,您将收到一个编译器错误,行为"必须具有类或枚举类型的参数"。为了提供运算符重载,您必须至少提供一个类或枚举型参数。


所以让我们思考一下。我们不能将operator<<与两个基元参数一起使用,因为这是不允许的。您真正想要的是没有任何显式初始化的干净初始化语法。唯一真正阻碍我们的是初始化。那么,如果我们试图构建一个实际上使用两个运算符的东西,但看起来仍然干净呢?如果我们试图构建这样的东西:

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

它并不是您想要的语法,但它相当接近。因此,让我们尝试构建这个:

这里有两个操作员在工作:operator<operator>operator<的参数是字符串文字"test1和一些名为MapTo的对象。operator>的自变量是operator<返回的任何值和一个整数字面值1

首先来看operator<,让我们破解一个原型:

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

我们知道我们希望operator>返回duo,那么Something需要是什么才能实现这一点?我们真正需要operator<做的就是将字符串文字转换为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);
}

这很容易。让我们把它放在一起(现场演示):

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

您正试图为两个基元类型char const *int重载operator>>;这是语言不允许的。要使其以当前形式工作,您需要从第一个参数显式创建一个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和int定义了运算符>>,但您试图将其与参数const char[]和int一起使用。您需要让编译器知道第一个参数是std::字符串。尝试{"test1"s >> 1}