[英]Error C2664: Cannot convert argument from initializer list to std:initializer list
我有一個 function read()
讀取文件並將信息存儲到 map 中。 但是,每當 function 調用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
具有相同的基數 class :)
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, 19);
ID = line.substr(20, 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, 19);
ID = line.substr(20, 29);
salary = std::stod(line.substr(30, T_LINE_SIZE));
input.insert({ name,new Employee(ID, name, salary) });
}
}
}
原因是您正在使用模板。 根據調用read()
function 時的T
類型,調用insert()
方法的一個if
條件的 scope 中的T
類型不正確。 發生這種情況是因為需要在編譯時針對不同類型檢查所有可能的代碼結果。 但是當你使用if constexpr
時,那部分代碼在編譯時會被忽略,所以在編譯代碼時不會看到不正確的部分代碼,你的代碼會正確編譯。
@Afshin 已經展示了一種可以做到這一點的方法,但我建議這可能不是完成這項工作的最佳方法,至少作為一項規則。
通過稍微不同地分配邏輯,您可以得到我認為相當簡單的代碼。
我將首先重載operator>>
以讀取您需要存儲的每個 class 的 object:
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, std::map<std::string, T *> &input) {
T t;
while (is >> t)
input.emplace(t.name, new T(t));
}
在這種設計中, Employee
和Volunteer
都知道如何從文件中讀取自己的數據,讀取記錄的代碼不需要知道如何讀取各自的詳細信息。 這使得代碼更具可擴展性。 例如,讓我們考慮當我們為Intern
添加進一步的 class 時會發生什么。 在您的原始代碼(由 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 class 本身:
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
而不是Employee
或Volunteer
的記錄文件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.