c++ - 如何使简单的循环更通用

标签 c++ c++11 templates c++14

下面的方法会将所有警告连接成一个字符串。它可以工作,但显然需要为信息和错误再次创建几乎相同的方法。

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';
}

而且,如果您的结构中有不同类型的成员(请注意,上述解决方案仅适用于 stringvector),您可以将 >连接到函数模板中:

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/

相关文章:

c++ - 力扣#15 : 3sum -- avoiding duplicate

typescript - 如何以最少的 react 性将 TypeScript 常量传递给 Vue 模板

xml - 如何在 XSLT 中从另一个模板调用模板?

c++ - 如何编写以可变参数作为模板参数的成员函数

c++ - std::function 中的冗余构造函数重载?

c++ - makefile 不适用于 -std=c++11 选项

c++ - add_definitions 与 configure_file

c++ - Qt raw 与 std::shared_ptr

c++ - vector 问题

c++ - glfwTerminate() 之后的代码永远不会运行