使用与滥用通用算法

时间:2015-07-10 08:52:02

标签: c++ c++11 stl-algorithm

为了使讨论具体化,假设一个简单的示例问题:用户输入几个没有空格的一位数字,按Enter并得到这些数字的总和。因此,用户会话可能如下所示:

> 1231
7
> 12
3
> 0123
6
> ^D

我正在通过 C ++ Primer (第5版)学习C ++。在学习关于泛型算法的第10章之前,我将以下面的天真方式解决上述问题:

int main() {
    std::cout << "> ";
    std::string word;
    while (std::cin >> word) {
        auto sum = 0;
        for (auto c : word) sum += c - '0';
        std::cout << sum << std::endl << "> ";
    }
    return 0;
} 

以下是我使用通用算法解决同样问题的方法:

int main() {
    std::cout << "> ";
    std::istream_iterator<std::string> in(std::cin), eof;
    std::for_each(in, eof,
                  [](const std::string &word) {
                      std::cout << std::accumulate
                          (word.cbegin(), word.cend(), 0,
                           [](int cur, char ch) {
                               return cur + (ch - '0');
                           }) << std::endl << "> ";
                  });
    return 0;
}

说实话,我更喜欢第一种解决方案。它简短易读。第二种解决方案牺牲了C ++ 11标准库的祭坛的简洁性和清晰度。

我的问题有三个:

  1. 我对两种解决方案的比较是否正确?

  2. 使用标准库的功能是否有更好的方法来解决示例问题?

  3. 如果在这种情况下天真的解决方案实际上是最好的解决方案,那么我在示例中使用的C ++ 11标准库的功能的实际用例是什么?

  4. 编辑:实际上,我应该完全使用I / O迭代器。清理一下后,这就是我得到的。有什么意见吗?

    int main() {
        std::cout << "> ";
        std::istream_iterator<std::string> in(std::cin), eof;
        std::ostream_iterator<int> out(std::cout, "\n> ");
        using CStrR = const std::string &;
        auto myAdd = [](int acc, char ch) {return acc + (ch - '0');};
        auto mySum = [&](CStrR word) {
            out = std::accumulate(word.cbegin(), word.cend(), 0, myAdd);
        };
        std::for_each(in, eof, mySum);
        return 0;
    }
    

3 个答案:

答案 0 :(得分:2)

你可以写得更简单。例如

auto sum = std::accumulate( std::istream_iterator<char>( std::cin ), 
                            std::istream_iterator<char>(),
                            0, []( auto acc, auto c ) { return acc += c -'0'; } ); 

std::cout << sum << std::endl;

或者

#include <iostream>
#include <numeric>
#include <string>

int main()
{
    std::cout << "> ";

    std::string word;

    while ( std::cin >> word ) 
    {
        auto sum = std::accumulate( word.begin(), word.end(), 0, 
                                    []( int acc, char c ) { return acc += c - '0'; } );
        std::cout << sum << std::endl << "> ";
    }
}    

虽然有时使用普通循环而不是复合算法记录确实更好。:)

答案 1 :(得分:0)

请记住,这只是一个玩具示例,可以让您更容易理解一些复杂的概念。在实践中,您可能不会看到这么简单的代码。

你永远不应该*牺牲代码的清晰度。当计算机变得更快,新标准出现时,建议使用新的编码样式,您编写的代码不易于阅读,理解或调试。

因此对于这个特殊问题,较短的版本很可能是你想要的。 例如,如果您想支持cin但也支持字符向量,那么第二个版本更合适,因为您必须进行少量更改,但您也可以修改第一个版本。

始终了解适用于手头问题的内容,保持简单,不要害怕修改项目代码。

答案 2 :(得分:0)

问题不在于一般方法是错误的,而且通常众所周知C ++ stdlib过于冗长。委员会正在研究实际范围,这将使这个问题变得更简单,但它们还没有完成。

一个好的块也是完全不必要的换行符和相关的缩进罪。

int main() {
    std::cout << "> ";
    std::istream_iterator<std::string> in(std::cin), eof;
    std::ostream_iterator<int> out(std::cout, "\n> ");
    std::for_each(in, eof, [&out](std::string word) {
        *out = std::accumulate(word.begin(), word.end(), 0, [](int cur, char ch) {
            return cur + (ch - '0');
        });
    });
    return 0;
}

如果您以合理的方式对其进行格式化,则会更具竞争力。

此外,最终,算法库不是为解决琐碎问题而构建的,它是为解决难题而构建的。