C++自定义struct向量ostream输出报错,求无重载的优雅实现方式
我写了一段遍历vector并打印内容的代码,处理自定义traits结构体的vector时出现报错,但char类型的vector可以正常输出。
报错信息
dfs.cpp:45:16: error: no match for ‘operator*’ (operand type is ‘const traits’) std::cout << *c << ' ';
dfs.cpp:44:15: error: cannot bind ‘std::ostream {aka std::basic_ostream}’ lvalue to ‘std::basic_ostream&&’ std::cout<<*v<<
原始代码
#include<iostream> #include<list> #include<vector> #include<stdio.h> using namespace std; struct traits { int x; bool visit; std::list<int> friends; }; int main() { cout << "Enter the number of employees: " << endl; int noOfEmployees, noOfFriends; cin>>noOfEmployees; std::vector<traits> employees; int i = 0; int j; while(noOfEmployees--){ traits v; v.x = i; cout << "Enter the no of friends: " << endl; cin >> noOfFriends; while(noOfFriends--){ cin>>j; v.friends.push_back(j); } v.visit = false; employees.push_back(v); i++; // 补充原始代码遗漏的自增逻辑,避免所有x值为0 } std::vector<char> path; path.push_back('a'); path.push_back('l'); path.push_back('i'); path.push_back('a'); for (std::vector<char>::const_iterator i = path.begin(); i != path.end(); ++i){ std::cout << *i << ' '; } for(std::vector<traits>::iterator v = employees.begin(); v != employees.end(); ++v){ std::cout<<*v<<endl; } }
我看过一些解决方案,但希望不使用运算符重载,请问更符合C++风格的正确实现方式是什么?
嗨,这个问题其实很好理解:std::cout知道怎么输出char、int这类内置类型,但它完全不知道你的自定义traits结构体该怎么打印——毕竟结构体里包含了int、bool还有list,没有默认的输出规则。既然不想重载operator<<,那咱们可以用这两种更贴合C++风格的方式解决:
方式1:遍历结构体时直接访问成员输出
这种方式最直接,在遍历employees的循环里,明确指定要打印结构体的每个成员,包括嵌套的list:
// 替换原来的traits遍历循环 for(std::vector<traits>::iterator v = employees.begin(); v != employees.end(); ++v){ std::cout << "Employee " << v->x << ": " << endl; std::cout << " Visited: " << (v->visit ? "Yes" : "No") << endl; std::cout << " Friends: "; // 遍历打印friends列表 for(std::list<int>::const_iterator f = v->friends.begin(); f != v->friends.end(); ++f){ std::cout << *f << " "; } std::cout << endl << endl; }
如果是C++11及以上版本,还可以用范围for循环让代码更简洁:
for(const auto& emp : employees){ std::cout << "Employee " << emp.x << ": " << endl; std::cout << " Visited: " << (emp.visit ? "Yes" : "No") << endl; std::cout << " Friends: "; for(int friend_id : emp.friends){ std::cout << friend_id << " "; } std::cout << endl << endl; }
方式2:封装一个专门的打印函数
如果需要多次打印traits对象,把打印逻辑封装成独立函数会更符合模块化思想,也让代码更整洁:
// 在main函数外定义打印函数 void print_traits(const traits& t){ std::cout << "Employee " << t.x << ": " << endl; std::cout << " Visited: " << (t.visit ? "Yes" : "No") << endl; std::cout << " Friends: "; for(int friend_id : t.friends){ std::cout << friend_id << " "; } std::cout << endl << endl; } // 在main里的遍历循环直接调用 for(const auto& emp : employees){ print_traits(emp); }
这两种方式都不需要重载运算符,而且完全符合C++的代码组织风格——要么直接明确输出逻辑,要么把重复逻辑封装成可复用的函数。
内容的提问来源于stack exchange,提问作者hasherBaba

