我知道当代码中没有任何令人困惑的for
循环时,代码会更好。在可能的情况下重用标准库算法总是好的。但是,我发现迭代器和算法的语法看起来真的很混乱。
我想从我当前的项目中提供一个真实的例子:我想将vector<vector<QString>> in
的内容复制到vector<QVariant> out
。我看不出:
for (int i = 0; i < in[0].size(); i++ )
{
if(in[0][i].isNull() || in[0][i].isEmpty() )
out[i] = "NONE";
else
out[i] = in[0][i];
}
那:
std::transform(in[0].begin(), in[0].end(), out.begin(), [](const QString& a)->QVariant{
if(a.isNull() || a.isEmpty() )
return "NONE";
else
return a;
});
由于我们有visual studio 2012,我甚至必须输入我的lambda的返回值。使用范围后:
in[0].map!( a => a.isNull() || a.isEmpty() ? "NONE" : a ).copy(out);
在D语言中,我无法使用上面的std::transform
代码。我甚至不确定它是否比基本for
循环更好。我的问题是:上面使用std::transform
的代码比for
循环好吗?
答案 0 :(得分:8)
至少在我看来,这里的主要问题是transform
只是工作的错误工具。
你要做的事情正是std::replace_copy_if
所做的事情,所以(没有什么大惊喜)它能更清楚地做到这一点。
我手边的机器上没有安装Qt,所以我冒昧地将QVariant
和QString
代码替换为std::vector<std::string>
,但我相信相同的基本思想也应该适用于Qt类型。
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <string>
int main() {
std::vector<std::string> input { "one", "two", "", "three" };
std::vector<std::string> output;
// copy input to output, replacing the appropriate strings:
std::replace_copy_if(input.begin(), input.end(),
std::back_inserter(output),
[](std::string const &s) { return s.empty(); },
"NONE");
// and display output to show the results:
std::copy(output.begin(), output.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
}
目前,这只是用NONE
替换空字符串,但添加空检查应该非常简单(当然,isNull
有意义的类型)。
根据上面的数据,我得到了你可能期望的结果:
one
two
NONE
three
然而,我应该补充一点,即使这显然是非常冗长的。当我们至少将范围添加到标准库时会很好,因此(例如)input.begin(), input.end()
可以仅用input
替换。结果仍然可能不会像你给出的D代码那样简洁,但至少它会稍微减少冗长(同样适用于大多数其他算法)。
如果您关心这一点,您可能需要查看几个range
个库 - Boost Range一个,(在我看来更有趣){{3} }。
答案 1 :(得分:3)
使用?
:
可以改进您的代码(创建一个可以使用的static QVariant QVNone;
可能是明智的。)
std::transform(in[0].begin(), in[0].end(), out.begin(),
[](const QString& a) // for C++14: (auto& a)
{ return a.isNull() || a.isEmpty() ? QVariant("NONE") : a; }
);
注意:this page文档QVariant(const QString&)
,因此编译器应该能够计算?
:
值的公共类型。
C ++ 11提供了单个return语句时lambda返回类型的自动确定 - 请参阅语法(3)here。 C ++ 14已经引入了接受参数ala (auto& a)
的能力。容器元素上的范围将有助于进一步简化这种循环;我认为他们已经提议用于C ++ 17;相关论文here。
还有用于C ++的功能(非标准)库可能会为您提供更像您为D文档提供的符号。图书馆建议在这里是偏离主题的,但Google应该不费吹灰之力就找出一些候选人。< / p>