首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有Lambda自动类型推导的recursive_count_if函数在C++中的各种类型任意嵌套迭代实现

具有Lambda自动类型推导的recursive_count_if函数在C++中的各种类型任意嵌套迭代实现
EN

Code Review用户
提问于 2020-11-18 15:40:58
回答 1查看 86关注 0票数 3

这是递推_计数_C++中各种类型任意嵌套Iterable实现的if函数递推_计数_具有指定值的if函数_C++中各种类型任意嵌套Iterable实现的类型的后续问题.在深入研究了检测函数的参数类型的内容之后,我发现可以用Boost.CallableTraits图书馆中的boost::callable_traits::args_t语法简化最后实现中的D5参数。因此,recursive_count_if模板函数完全可以作为以下代码使用。

代码语言:javascript
复制
std::vector> v = {{"hello"}, {"world"}};
auto size5 = [](std::string s) { return s.size() == 5; };
auto n = recursive_count_if(v, size5);

recursive_count_if函数的自动类型推导实现:

代码语言:javascript
复制
#include 
//  recursive_count_if implementation
template requires (is_iterable && std::same_as>, boost::callable_traits::args_t>)
auto recursive_count_if(const T1& input, const T2 predicate)
{
    return std::count_if(input.begin(), input.end(), predicate);
}

//  transform_reduce version
template requires (is_iterable && !std::same_as>, boost::callable_traits::args_t>)
auto recursive_count_if(const T1& input, const T2 predicate)
{
    return std::transform_reduce(std::begin(input), std::end(input), std::size_t{}, std::plus(), [predicate](auto& element) {
        return recursive_count_if(element, predicate);
        });
}

使用的is_iterable概念:

代码语言:javascript
复制
template
concept is_iterable = requires(T x)
{
    *std::begin(x);
    std::end(x);
};

使用的The约束

因为输入lambda函数中的类型扮演终止条件的角色,所以这里不能使用auto关键字作为泛型lambda。如果传入类似于[](auto element) { }的lambda函数,编译错误将弹出。如果要使用泛型lambdas,可能可以选择上一版本recursive_count_if函数,因为终止条件是分开的。

上帝的链接在这里。

欢迎所有建议。

摘要资料:

EN

回答 1

Code Review用户

回答已采纳

发布于 2020-11-19 16:37:43

不要试图推断谓词的参数类型

由于库克斯普鲁松在前面问题的注释中,不应该尝试确定谓词函数参数的类型,这肯定会失败。实际上,当您查看谓词时,问题立即开始:

代码语言:javascript
复制
auto size5 = [](std::string s) { return s.size() == 5; };

想一想:嘿,那是在复制s,我应该把它传递给const reference:

代码语言:javascript
复制
auto size5 = [](const std::string &s) { return s.size() == 5; };

现在,函数的requires子句失败了。在将类型与std::same_as进行比较之前,您可能可以添加更多的技巧来丢弃cv-限定符和引用,但这也不能涵盖所有可能的情况。例如,我可以编写一个lambda,它允许检查任何类型的std::basic_string

代码语言:javascript
复制
auto size5 = [](std::basic_string s) { return s.size() == 5; };

正如我在注释中所建议的那样,您只想编写一个概念,检查谓词是否可以应用于其输入的参数,而不需要检查类型本身。以下是一个可能的实现:

代码语言:javascript
复制
template
concept is_applicable_to_elements = requires(Pred predicate, const T &container)
{
    predicate(*container.begin());
};

template requires is_applicable_to_elements
auto recursive_count_if(const T1& input, const T2 predicate)
{
    return std::count_if(input.begin(), input.end(), predicate);
}

template
auto recursive_count_if(const T1& input, const T2 predicate)
{
    return std::transform_reduce(std::begin(input), std::end(input), std::size_t{}, std::plus(), [predicate](auto& element) {
        return recursive_count_if(element, predicate);
    });
}

注意,由于所有模板都使用了is_iterable(),所以可以删除该要求,但是如果保留它,如果您不小心尝试将recursive_count_if()应用于不支持迭代的东西,则会得到更好的错误消息。

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/252325

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档