下面的方法会将所有警告连接成一个字符串。它可以工作,但显然需要为信息和错误再次创建几乎相同的方法。
struct MyItem
{
std::vector<std::string> errors;
std::vector<std::string> warnings;
std::vector<std::string> infos;
};
std::vector<MyItem> items;
std::string GetWarnings()
{
std::string str;
for (auto item : items)
{
for (auto warn : item.warnings)
{
str += warn;
str += " ";
}
}
return str;
}
实现一个“连接”方法的通用方法是什么?一种解决方案是定义一个枚举(错误\警告\项目),将其作为输入参数传递,并对参数值进行切换。还有更优雅的解决方案吗?
最佳答案
您可以使用指向成员的指针从对象中提取特定字段:
auto concatenate(
const std::vector<MyItem>& items,
const std::vector<std::string> MyItem::* member
) {
std::string str;
for (const auto& item : items) {
for (const auto& element : item.*member) {
str += element;
str += " ";
}
}
return str;
}
可以像这样使用:
int main() {
std::vector<MyItem> items{
{{"err11", "err12"}, {"w11"}, {"i11", "i12", "i13"}},
{{"err21"}, {"w21", "w22", "w23", "w24"}, {"i21"}}
};
std::cout << "all errors: " << concatenate(items, &MyItem::errors) << '\n'
<< "all warnings: " << concatenate(items, &MyItem::warnings) << '\n'
<< "all infos: " << concatenate(items, &MyItem::infos) << '\n';
}
而且,如果您的结构中有不同类型的成员(请注意,上述解决方案仅适用于 string
的 vector
),您可以将 >连接
到函数模板
中:
struct MyItem {
std::vector<std::string> errors;
std::vector<std::string> warnings;
std::vector<std::string> infos;
std::vector<char> stuff; // added
};
template <typename T> // now a function template
auto concatenate(
const std::vector<MyItem>& items,
const T MyItem::* member
) {
std::string str;
for (const auto& item : items) {
for (const auto& element : item.*member) {
str += element;
str += " ";
}
}
return str;
}
int main() {
std::vector<MyItem> items{
{{"err11", "err12"}, {"w11"}, {"i11", "i12", "i13"}, {'1' ,'2'}},
{{"err21"}, {"w21", "w22", "w23", "w24"}, {"i21"}, {'3'}}
};
std::cout << "all errors: " << concatenate(items, &MyItem::errors) << '\n'
<< "all warnings: " << concatenate(items, &MyItem::warnings) << '\n'
<< "all infos: " << concatenate(items, &MyItem::infos) << '\n'
<< "all stuffs: " << concatenate(items, &MyItem::stuff) << '\n';
}
请注意,我还将 for()
循环中的 auto item
事件更改为 const auto& item
以避免不必要的复制.
或者,您可以使用投影来提取元素。在此实现中,我们使用 template
接受任何类型的函数,该函数将采用您的 MyItem
并返回所需的元素:
template <typename Proj>
auto concatenate(
const std::vector<MyItem>& items,
Proj projection
) {
std::string str;
for (const auto& item : items) {
for (const auto& element : projection(item)) {
str += element;
str += " ";
}
}
return str;
}
int main() {
std::vector<MyItem> items{
{{"err11", "err12"}, {"w11"}, {"i11", "i12", "i13"}, {'1' ,'2'}},
{{"err21"}, {"w21", "w22", "w23", "w24"}, {"i21"}, {'3'}}
};
auto errors_projection =
[](const MyItem& item) -> const std::vector<std::string>& {
return item.errors;
};
auto warnings_projection =
[](const MyItem& item) -> const std::vector<std::string>& {
return item.warnings;
};
auto infos_projection =
[](const MyItem& item) -> const std::vector<std::string>& {
return item.infos;
};
auto stuff_projection =
[](const MyItem& item) -> const std::vector<char>& {
return item.stuff;
};
std::cout << "all errors: " << concatenate(items, errors_projection) << '\n'
<< "all warnings: " << concatenate(items, warnings_projection) << '\n'
<< "all infos: " << concatenate(items, infos_projection) << '\n'
<< "all stuffs: " << concatenate(items, stuff_projection) << '\n';
}
关于c++ - 如何使简单的循环更通用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69337471/