我目前正在学习 C++17,作为练习使用标准库的一部分,我们遇到了一个挑战,以习惯使用这些功能:
- 循环访问
std::map<std::string, size_t>
(也称为std::map<file_name, file_size>
( - 打印空
size_t == 0
文件名并返回其计数 - 打印非空
size_t != 0
文件名并返回其计数 - 从地图
std::pairs
whose size_t == 0
中删除
限制:
-
只能使用标头:
<vector>
、<map>
、<string>
、<algorithm>
、<functional>
-
无法定义复杂类型或模板
-
无法使用
. (member access), -> (member access via pointer), * (dereference) operators
-
不能使用
for, while, do-while nor if-else, switch
和其他条件 -
可以使用函数模板的
std::for_each
和其他函数来迭代元素集合 -
无λ
-
没有
std::cout
、std::cerr
、std::ostream
等。 -
无自动类型
-
可以使用其他函数,只要它们包含在限制 #1 中描述的标头中
允许使用以下函数:
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;
}
在我之前的帖子中,我开始欣赏std::bind
和std::for_each
的使用。这一次,如何在不使用限制 #4 所述的语法的情况下添加谓词和条件来修改输出?
我目前正在考虑使用std::transform()
或std::copy_if()
等。我对标准库的许多功能都有一些了解,但我认为我在语法上非常薄弱,无法理解事物如何协同工作,因此我不知道如何使用它们。
对于 2,3 个任务,您可以执行:
- 使用初始大小的
vector
作为地图大小 - 使用
copy_if
根据条件从地图复制元素 - 将
for_each
与有界split
/print
一起使用 - 返回 Vector 中第一个项和最后一个项之间的差项数
代码:
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
的项目。要从映射中删除元素,您可以在 vector 中迭代这些项目(使用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)) );
}
完整演示