如何解决错误 C2664:无法将参数从初始化列表转换为 std:初始化列表
我有一个函数 read()
可以读取文件并将信息存储到地图中。但是,每当函数调用 map.insert()
时,它都会给我一个错误。
Employee
和 Volunteer
是两个只有几个变量的海关类。
例如,如果我打电话
ifstream fin;
std::map<std::string,Employee*> employees;
fin.open("Employee.txt");
read<Employee,EMPLOYEE_SIZE>(fin,employees);
它给出了以下错误:
std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::insert(std::initializer_list<std::pair<const std::string,Employee *>>)': cannot convert argument 1 from 'initializer list' to 'std::initializer_list<std::pair<const std::string,Employee *>>'`.
这是函数(Employee
和 Volunteer
具有相同的基类:)
template <typename T,int T_LINE_SIZE>
inline void read(std::ifstream& in,std::map<std::string,T*>& input) {
std::string name = "";
std::string ID="";
std::string line;
double salary;
while (getline(in,line)) {
if (typeid(T) == typeid(Volunteer)) {
name = line.substr(0,19);
ID = line.substr(20,T_LINE_SIZE);
input.insert({name,new Volunteer(ID,name)}); //error happens here
}else if (typeid(T) == typeid(Employee)) {
name = line.substr(0,29);
salary = std::stod(line.substr(30,T_LINE_SIZE));
input.insert({ name,new Employee(ID,name,salary) }); //error happens here
}
}
}
我在这里做错了什么?
解决方法
试试下面的代码:
template <typename T,int T_LINE_SIZE>
inline void read(std::ifstream& in,std::map<std::string,T*>& input) {
std::string name = "";
std::string ID="";
std::string line;
double salary;
while (getline(in,line)) {
if constexpr (std::is_same<T,Volunteer>::value) {
name = line.substr(0,19);
ID = line.substr(20,T_LINE_SIZE);
input.insert({name,new Volunteer(ID,name)});
}else if constexpr (std::is_same<T,Employee>::value) {
name = line.substr(0,29);
salary = std::stod(line.substr(30,T_LINE_SIZE));
input.insert({ name,new Employee(ID,name,salary) });
}
}
}
原因是您正在使用模板。根据调用 T
函数时 read()
的类型,T
的类型在调用 if
方法的一个 insert()
条件范围内是不正确的。发生这种情况是因为需要在编译时针对不同类型检查代码的所有可能结果。但是当您使用 if constexpr
时,那部分代码在编译时会被忽略,因此在编译代码时不会看到错误的代码部分,并且您的代码编译正确。
@Afshin 展示了一种您可以做到这一点的方式,但我认为这可能不是完成这项工作的最佳方式,至少作为一项规则。
通过稍微不同地分配逻辑,你最终可以得到我认为相当简单的代码。
我将首先重载 operator>>
以读取您需要存储的每个类的对象:
struct Volunteer {
std::string name;
std::string ID;
friend std::istream &operator>>(std::istream &is,Volunteer &v) {
std::string line;
std::getline(is,line);
v.name = line.substr(0,19);
v.ID = line.substr(20); // captures the rest of the line
return is;
}
};
struct Employee {
std::string name;
std::string ID;
double salary;
friend std::istream &operator>>(std::istream &is,Employee &e) {
std::string line;
std::getline(is,line);
e.name = line.substr(0,19);
e.ID = line.substr(20,29);
e.salary = std::stod(line.substr(30);
return is;
}
};
我可能在 Volunteer
和 Employee
中省略了其他(可能很重要)的东西——我只包含了足以从文件中读取一个并存储我们读取的数据的内容。
有了这些,从文件中读取它们变得相当简单:
template <class T>
inline void read(std::istream &is,T *> &input) {
T t;
while (is >> t)
input.emplace(t.name,new T(t));
}
在这个设计中,Employee
s 和 Volunteer
s 都知道如何从文件中读取自己的数据,读取记录的代码不需要知道每个已读。这使得代码更具可扩展性。例如,让我们考虑为 Intern
添加另一个类时会发生什么。在您的原始代码中(由 Afshin 修复),您将向 if
/else if
链添加第三条腿:
else if constexpr (std::is_same<T,Intern>::value) {
// code to read and insert data for an Intern here
}
相比之下,在我提倡的设计中,所有处理 Intern 的代码都在(或至少与)Intern 类本身相关:
struct Intern {
std::string name;
std::string ID;
bool paid;
double salary;
friend std::istream &operator>>(std::istream &is,Intern &i) {
// code to read data for an Intern here
}
};
...因此,在这种情况下,从文件读取数据的代码不需要任何更改即可处理 Intern
的记录文件而不是 {{ 1}} 或 Employee
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。