提供正确的 std::copy_if 谓词
Providing a correct std::copy_if predicate
示例程序的目的是将 source
中的每三个项目复制到 std::copy_if
的目标。
基于 reference,只要谓词 return 为真,复制就会发生,但下面的代码不是这种情况。
#include <iostream>
#include <vector>
#include <algorithm>
using std::vector;
int main(int argc, char** agrs){
vector<double> source(15, 0.5);
vector<double> target(15, 1.1);
int index = 0;
std::copy_if(
source.begin(),source.end(),target.begin(),
[&](double number){
index = ((index + 1) % 3);
std::cout << "["<< index << "]->" << (0 == index) << "\t";
return (0 == index);
}
);
std::cout << std::endl;
std::for_each(source.begin(),source.end(),[](double value){
std::cout << "["<< value << "]\t";
});
std::cout << std::endl;
std::for_each(target.begin(),target.end(),[](double value){
std::cout << "["<< value << "]\t";
});
std::cout << std::endl;
return 0;
}
输出如下:
[1]->0 [2]->0 [0]->1 [1]->0 [2]->0 [0]->1 [1]->0 [2]->0 [0]->1 [1]->0 [2]->0 [0]->1 [1]->0 [2]->0 [0]->1
[0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5]
[0.5] [0.5] [0.5] [0.5] [0.5] [1.1] [1.1] [1.1] [1.1] [1.1] [1.1] [1.1] [1.1] [1.1] [1.1]
第一行显示实际复制以及输出谓词的 return 值。
第二行是源向量,第三行是目标向量。
根据谓词,期望每个第 3 个元素都被复制是公平的,但事实并非如此?
这是为什么?如何固定逻辑以实现其预期目的?
不幸的是,有时 cplusplus 有 wrong/misleading 信息。 They write:
result
Output iterator to the initial position of the range where the resulting sequence is stored. The range includes as many elements as [first,last).
这是错误的。输出范围具有与谓词 returns true
一样多的元素。在这种情况下,不会复制其他对象,并且不会增加目标迭代器。 copy_if
与您的示例中预期的一样工作。
我建议参考:https://en.cppreference.com/w/cpp/algorithm/copy
它也没有明确提到输出迭代器仅在实际复制元素时才前进。但它也没有另有说明。查看可能的实现应该会使事情更清楚:
template<class InputIt, class OutputIt, class UnaryPredicate>
OutputIt copy_if(InputIt first, InputIt last,
OutputIt d_first, UnaryPredicate pred)
{
while (first != last) {
if (pred(*first))
*d_first++ = *first;
first++;
}
return d_first;
}
可以看到d_first
只有在pred(*first)
returns true
.
的时候才会递增
示例程序的目的是将 source
中的每三个项目复制到 std::copy_if
的目标。
基于 reference,只要谓词 return 为真,复制就会发生,但下面的代码不是这种情况。
#include <iostream>
#include <vector>
#include <algorithm>
using std::vector;
int main(int argc, char** agrs){
vector<double> source(15, 0.5);
vector<double> target(15, 1.1);
int index = 0;
std::copy_if(
source.begin(),source.end(),target.begin(),
[&](double number){
index = ((index + 1) % 3);
std::cout << "["<< index << "]->" << (0 == index) << "\t";
return (0 == index);
}
);
std::cout << std::endl;
std::for_each(source.begin(),source.end(),[](double value){
std::cout << "["<< value << "]\t";
});
std::cout << std::endl;
std::for_each(target.begin(),target.end(),[](double value){
std::cout << "["<< value << "]\t";
});
std::cout << std::endl;
return 0;
}
输出如下:
[1]->0 [2]->0 [0]->1 [1]->0 [2]->0 [0]->1 [1]->0 [2]->0 [0]->1 [1]->0 [2]->0 [0]->1 [1]->0 [2]->0 [0]->1
[0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5] [0.5]
[0.5] [0.5] [0.5] [0.5] [0.5] [1.1] [1.1] [1.1] [1.1] [1.1] [1.1] [1.1] [1.1] [1.1] [1.1]
第一行显示实际复制以及输出谓词的 return 值。 第二行是源向量,第三行是目标向量。
根据谓词,期望每个第 3 个元素都被复制是公平的,但事实并非如此?
这是为什么?如何固定逻辑以实现其预期目的?
不幸的是,有时 cplusplus 有 wrong/misleading 信息。 They write:
result
Output iterator to the initial position of the range where the resulting sequence is stored. The range includes as many elements as [first,last).
这是错误的。输出范围具有与谓词 returns true
一样多的元素。在这种情况下,不会复制其他对象,并且不会增加目标迭代器。 copy_if
与您的示例中预期的一样工作。
我建议参考:https://en.cppreference.com/w/cpp/algorithm/copy
它也没有明确提到输出迭代器仅在实际复制元素时才前进。但它也没有另有说明。查看可能的实现应该会使事情更清楚:
template<class InputIt, class OutputIt, class UnaryPredicate> OutputIt copy_if(InputIt first, InputIt last, OutputIt d_first, UnaryPredicate pred) { while (first != last) { if (pred(*first)) *d_first++ = *first; first++; } return d_first; }
可以看到d_first
只有在pred(*first)
returns true
.