条件打印和计数超过 std::map 有限制

Conditional printing and counting over std::map with restrictions

我目前正在学习 C++17,在练习使用标准库以习惯使用这些功能的过程中,我们遇到了挑战:

  1. 迭代 std::map<std::string, size_t>(也称为 std::map<file_name, file_size>
  2. 打印空文件名 size_t == 0 和 return 计数
  3. 打印不为空的文件名 size_t != 0 和 return 计数
  4. 正在从地图中删除 std::pairs whose size_t == 0

限制:

  1. 只能使用headers: <vector>, <map>, <string>, <algorithm>, <functional>

  2. 不能定义复杂类型和模板

  3. 无法使用 . (member access), -> (member access via pointer), * (dereference) operators

  4. 不能使用for, while, do-while nor if-else, switch和其他条件

  5. 可以使用std::for_each和函数模板的其他函数迭代collection个元素

  6. 没有 lambdas

  7. std::coutstd::cerrstd::ostream

  8. 没有自动类型

  9. 可以使用其他功能,只要它们包含在限制 #1

  10. 中描述的 headers 中

允许使用这些功能:

void print(const std::string& str)
{
    std::cout << str << std::endl;
}
std::string split(const std::pair<std::string, size_t> &r)
{
    std::string name;
    std::tie(name, std::ignore) = r;
    return name;
}
bool checkEmpty(const std::pair<std::string, size_t>& r, bool trueIfIsNot
)
{
    file_size size;
    std::tie(std::ignore, size) = r;
    bool result = (size == 0);
    if (trueIfIsNot)
    {
        result = !result;
    }
    return result;
}

我开始欣赏在我之前的 post 中使用 std::bindstd::for_each。这一次,我如何添加谓词和条件来修改输出而不使用限制 #4 规定的语法?

我目前正在考虑使用 std::transform()std::copy_if() 等。我对标准库的许多功能有一些了解,但我认为我在语法方面非常薄弱,无法理解其工作原理在一起所以我不知道如何使用它们。

您可以完成 2,3 项任务:

  • 使用 vector 初始大小作为地图大小
  • 使用copy_if根据条件从地图复制元素
  • 使用 for_each 有界 split/print
  • return 项目数作为向量中第一项和最后一项之间的差异

代码:

int task2and3(const std::map<std::string,int>& m, bool trueIfIsNot)
{
    std::vector<std::pair<std::string,int>> vec(m.size());
    auto firstPastEnd = std::copy_if(m.begin(),m.end(),vec.begin(),
        std::bind(checkEmpty,std::placeholders::_1,trueIfIsNot));

    std::for_each(vec.begin(), firstPastEnd, 
        std::bind(print,std::bind(split,std::placeholders::_1)));

    return firstPastEnd - vec.begin();
}

通过 trueIfIsNot 指示打印了哪些对(值为 0 或其他)。


要完成第 4 个任务,您还可以使用 vector 来存储 map 的项目。要从地图中删除元素,您可以在向量中迭代这些项目(使用 for_each)并调用 map::erase 方法。因为这个函数成员有重载,所以你需要正确地转换它以指示方法通过 key_type 删除元素。使用 split 从对中得到这个 key_type

void task4(std::map<std::string,int>& m)
{
    std::vector<std::pair<std::string,int>> vec(m.size());
    auto firstPastEnd = std::copy_if(m.begin(),m.end(),vec.begin(),std::bind(checkEmpty,std::placeholders::_1,false));

    using sizeType = std::map<std::string,int>::size_type;
    using keyType = std::map<std::string,int>::key_type;

    for_each(vec.begin(), firstPastEnd, 
        std::bind( static_cast<sizeType (std::map<std::string,int>::*)(const keyType&) >(&std::map<std::string,int>::erase),
        &m,
        std::bind(split,std::placeholders::_1)) );
}

Full demo