我创建了一个呈现数据表的代码。我想使其更通用。
我的代码:
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
struct Student
{
std::string name;
unsigned points;
unsigned height;
unsigned weight;
};
namespace console
{
constexpr unsigned max_chars_in_line = 79;
void draw_line(unsigned count = max_chars_in_line, char sign = '-')
{
std::cout << std::string(count, sign) << "\n";
}
}
int main()
{
std::cout << std::fixed << std::setprecision(2);
std::vector<Student> students
{
{ "John", 30, 200, 300 },
{ "Peter", 80, 160, 80 },
{ "Albert", 200, 175, 1230 },
{ "Hans", 100, 178, 130 }
};
console::draw_line(45);
std::cout
<< std::right
<< std::setw(10) << "name"
<< std::setw(10) << "points"
<< std::setw(10) << "height"
<< std::setw(10) << "weight"
<< "\n";
console::draw_line(45);
for (auto& student : students)
{
std::cout
<< std::setw(10) << student.name
<< std::setw(10) << student.points
<< std::setw(10) << student.height
<< std::setw(10) << student.weight
<< "\n";
}
console::draw_line(45);
std::cout << "\n\n";
auto total_weight = std::accumulate(students.begin(), students.end(), 0u, [](unsigned sum, const Student& student) {return sum += student.weight; });
std::sort(students.begin(), students.end(), [](const Student& a, const Student& b) {return a.weight > b.weight; });
console::draw_line(40);
std::cout
<< std::setw(10) << "name"
<< std::setw(10) << "weight"
<< std::setw(15) << "percent (%)"
<< "\n";
console::draw_line(40);
for (auto& student : students)
{
std::cout
<< std::setw(10) << student.name
<< std::setw(10) << student.weight
<< std::setw(15) << 100 * static_cast<double>(student.weight) / total_weight
<< "\n";
}
console::draw_line(40);
std::cout
<< std::setw(10) << "total"
<< std::setw(10) << total_weight
<< std::setw(15) << 100.
<< "\n";
console::draw_line(40);
}
我希望代码看起来如何:
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <functional>
#include <fstream>
#include <numeric>
#include <string>
#include <vector>
struct Student
{
std::string name;
unsigned points;
unsigned height;
unsigned weight;
};
class GridView { /*...*/ };
int main()
{
std::cout << std::fixed << std::setprecision(2);
std::vector<Student> students
{
{ "John", 30, 200, 300 },
{ "Peter", 80, 160, 80 },
{ "Albert", 200, 175, 1230 },
{ "Hans", 100, 178, 130 }
};
GridView<Student> diagram1(&students); // pointer?
diagram1.addCol("name", &Student::name);
diagram1.addCol("points", &Student::points);
diagram1.addCol("height", &Student::height);
diagram1.addCol("weight", &Student::weight);
diagram1.print(std::cout); // or |std::cout << diagram1;|
std::cout << "\n\n";
auto total_weight = std::accumulate(students.begin(), students.end(), 0u, [](unsigned sum, const Student& student) {return sum += student.weight; });
std::sort(students.begin(), students.end(), [](const Student& a, const Student& b) {return a.weight > b.weight; });
std::ofstream file("grid.txt");
if (!file.is_open())
{
return -1;
}
GridView<Student> diagram2(&students);
diagram2.addCol("name", &Student::name, 10);
diagram2.addCol("weight", &Student::weight, 10);
diagram2.addCol("percent (%)", [=]() {return 100 * static_cast<double>(Student::weight) / total_weight; }, 15); // bind? how to do it?
diagram2.addFooter("total", total_weight, 100.);
diagram2.print(file);
}
我应该如何开始编写GridView类?加百分数的列应该是什么样的?也许我可以做得更好(更好)?看来我的帖子大部分是代码;抱歉,细节太少了。
编辑:代码:
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <functional>
#include <fstream>
#include <numeric>
#include <string>
#include <vector>
#include <variant>
struct Student
{
std::string name;
unsigned points;
unsigned height;
unsigned weight;
};
template <typename DataType>
class GridView
{
std::vector<DataType>* data_ptr;
using variant_cell_type = std::variant<int, float, double, unsigned, std::string>;
struct output_visitor
{
std::ostream& out;
output_visitor(std::ostream& out)
:out(out)
{
}
template <typename T>
void operator() (const T& value) const
{
out << value;
}
};
struct Col
{
std::string name;
std::function<variant_cell_type(DataType&)> access_data;
unsigned width;
};
std::vector<Col> cols;
unsigned max_chars_in_line;
std::vector<variant_cell_type> footer;
public:
GridView(std::vector<DataType>* data_ptr)
:data_ptr(data_ptr)
{
max_chars_in_line = 5;
}
template <class Magic, class Type>
void addCol(const std::string& colName, Magic Type::* ceilType, unsigned width = 10)
{
cols.push_back({colName, std::mem_fn(ceilType), width});
max_chars_in_line += width;
}
void addFooter(const std::vector<variant_cell_type>& footer)
{
this->footer = footer;
}
void print(std::ostream& out)
{
using std::string;
out << std::right;
out << string(max_chars_in_line, '-') << "\n";
for (auto& col : cols)
{
out << std::setw(col.width) << col.name;
}
out << "\n";
out << string(max_chars_in_line, '-') << "\n";
for (auto student : *data_ptr)
{
for (auto& col : cols)
{
out << std::setw(col.width);
std::visit(output_visitor{out}, col.access_data(student));
}
out << "\n";
}
if (footer.size() != 0)
{
if (footer.size() != cols.size())
{
throw std::invalid_argument("Footer must have " + std::to_string(cols.size()) + " arguments.");
}
out << string(max_chars_in_line, '-') << "\n";
auto foo = std::begin(footer);
auto col = std::begin(cols);
for (; foo != footer.end(); ++foo, ++col)
{
out << std::setw(col->width);
std::visit(output_visitor{ out }, *foo);
}
out << "\n";
}
out << string(max_chars_in_line, '-') << "\n";
}
};
int main()
{
std::cout << std::fixed << std::setprecision(2);
std::vector<Student> students
{
{ "John", 30, 200, 300 },
{ "Peter", 80, 160, 80 },
{ "Albert", 200, 175, 1230 },
{ "Hans", 100, 178, 130 }
};
try
{
GridView<Student> diagram1(&students);
diagram1.addCol("name", &Student::name);
diagram1.addCol("points", &Student::points);
diagram1.addCol("height", &Student::height);
diagram1.addCol("weight", &Student::weight);
diagram1.print(std::cout);
std::cout << "\n\n";
auto total_weight = std::accumulate(students.begin(), students.end(), 0u, [](unsigned sum, const Student& student) {return sum += student.weight; });
std::sort(students.begin(), students.end(), [](const Student& a, const Student& b) {return a.weight > b.weight; });
GridView<Student> diagram2(&students);
diagram2.addCol("name", &Student::name, 10);
diagram2.addCol("weight", &Student::weight, 10);
//auto calculate_weight = [=](Student student) {return 100 * static_cast<double>(student.weight) / total_weight; };
//diagram2.addCol("percent (%)", calculate_weight, 15); // bind? how to do it?
diagram2.addFooter({ "total", total_weight/*, 100.*/ });
diagram2.print(std::cout);
}
catch (const std::exception& e)
{
std::cerr << e.what() << "\n";
}
}
我该怎么做才能使注释片段起作用?