如何使用概念正确约束基于迭代器的函数
How to properly constrain an iterator based function using concepts
我无法理解 header 中定义的概念。我找不到使用它们的好例子。
我尝试在一个简单的函数中使用这些概念来提供更好的错误消息。我不明白为什么 output_iterator 需要一个类型而 input_iterator 没有。此外,我不知道如何使 random_assign_working
函数更通用。
template<typename T, std::input_iterator InputIter, std::output_iterator<T> OutputIter>
requires std::random_access_iterator<InputIter>
auto random_assign(InputIter inputBegin, InputIter inputEnd, OutputIter outBegin) {
auto inputSize = std::distance(inputBegin, inputEnd);
for (size_t it = 0; it < inputSize; it++) {
auto randomIndex = rand()%inputSize;
auto selectedInput = inputBegin[randomIndex]; // read input
*outBegin = selectedInput; // write output
outBegin++;
}
}
template<std::input_iterator InputIter, std::output_iterator<uint32_t> OutputIter>
requires std::random_access_iterator<InputIter>
auto random_assign_working(InputIter inputBegin, InputIter inputEnd, OutputIter outBegin) {
auto inputSize = std::distance(inputBegin, inputEnd);
for (size_t it = 0; it < inputSize; it++) {
auto randomIndex = rand()%inputSize;
auto selectedInput = inputBegin[randomIndex]; // read input
*outBegin = selectedInput; // write output
outBegin++;
}
}
int main() {
{
std::array<uint32_t, 9> input = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
std::forward_list<uint32_t> output;
random_assign(input.begin(), input.end(), std::front_insert_iterator(output)); // how can I make this work
random_assign_working(input.begin(), input.end(), std::front_insert_iterator(output)); // working
std::stringstream buf {};
buf << "Out ";
for (auto item : output)
buf << " " << item;
std::cout << buf.str() << std::endl;
}
{
std::array<std::string, 9> input = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
std::vector<std::string> output;
output.reserve(input.size());
random_assign(input.begin(), input.end(), output.begin()); // how can I make this work
random_assign_working(input.begin(), input.end(), std::front_insert_iterator(output)); // how can I make this work
}
}
所以我的问题是:
如何在编写函数时利用 中定义的概念。
iterator_tags 如何与此相关联?
如何检查 iterator_tags?
我很感激学习资源并为我指明正确的方向。
I don't understand why the output_iterator
takes a type but input_iterator
doesn't any.
因为输入迭代器具有具体类型:它是您从 *it
获得的类型。那就是迭代器的引用类型(iter_reference_t<I>
).
但输出迭代器没有 - 它们只有一组类型,您可以写入它们。 *out
给你什么并不重要,重要的是你可以将什么类型放入 *out = x;
你不能要求像...给我所有可能的类型,你可以写进我的预期输出迭代器类型,O
。但是您可以询问 O
是否接受 specific 类型 T
.
例如,int*
是一个输入迭代器,其引用类型为 int&
。但是 int*
也可以用作输出迭代器 - 但适用于多种类型。 int
当然,还有 int16_t
,或 uint64_t
,或 char
,或任何其他可转换为 int
.
的类型
因此,您可以询问 I
是否是 input_iterator
,但您只能询问 O
是否是您正在写入的某些类型的 output_iterator
它 T
.
让我们来看看你的 random_assign
:
template<typename T, std::input_iterator InputIter, std::output_iterator<T> OutputIter>
requires std::random_access_iterator<InputIter>
auto random_assign(InputIter inputBegin, InputIter inputEnd, OutputIter outBegin);
首先,random_access_iterator
优化了 input_iterator
,因此您无需同时编写两者。只需选择最具体的约束。一旦你这样做了,你写入 outBegin
的类型就是你的输入迭代器的引用类型,所以这就是你需要的约束:
template <std::random_access_iterator I, std::output_iterator<std::iter_reference_t<I>> O>
void random_assign(I first, I last, O out);
接下来,您想要return有用的信息。在这种情况下,我们要前进 out
很多次,所以我们应该 return 它的新值。
全部内容:
template <std::random_access_iterator I, std::output_iterator<std::iter_reference_t<I>> O>
auto random_assign(I first, I last, O out) -> O {
// you can use distance, but we know it's random access
size_t const dist = last - first;
for (size_t i = 0; i != dist; ++i) {
// output_iterator requires this work
*out++ = first[rand() % dist];
}
// law of useful return
return out;
}
我无法理解
我尝试在一个简单的函数中使用这些概念来提供更好的错误消息。我不明白为什么 output_iterator 需要一个类型而 input_iterator 没有。此外,我不知道如何使 random_assign_working
函数更通用。
template<typename T, std::input_iterator InputIter, std::output_iterator<T> OutputIter>
requires std::random_access_iterator<InputIter>
auto random_assign(InputIter inputBegin, InputIter inputEnd, OutputIter outBegin) {
auto inputSize = std::distance(inputBegin, inputEnd);
for (size_t it = 0; it < inputSize; it++) {
auto randomIndex = rand()%inputSize;
auto selectedInput = inputBegin[randomIndex]; // read input
*outBegin = selectedInput; // write output
outBegin++;
}
}
template<std::input_iterator InputIter, std::output_iterator<uint32_t> OutputIter>
requires std::random_access_iterator<InputIter>
auto random_assign_working(InputIter inputBegin, InputIter inputEnd, OutputIter outBegin) {
auto inputSize = std::distance(inputBegin, inputEnd);
for (size_t it = 0; it < inputSize; it++) {
auto randomIndex = rand()%inputSize;
auto selectedInput = inputBegin[randomIndex]; // read input
*outBegin = selectedInput; // write output
outBegin++;
}
}
int main() {
{
std::array<uint32_t, 9> input = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
std::forward_list<uint32_t> output;
random_assign(input.begin(), input.end(), std::front_insert_iterator(output)); // how can I make this work
random_assign_working(input.begin(), input.end(), std::front_insert_iterator(output)); // working
std::stringstream buf {};
buf << "Out ";
for (auto item : output)
buf << " " << item;
std::cout << buf.str() << std::endl;
}
{
std::array<std::string, 9> input = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
std::vector<std::string> output;
output.reserve(input.size());
random_assign(input.begin(), input.end(), output.begin()); // how can I make this work
random_assign_working(input.begin(), input.end(), std::front_insert_iterator(output)); // how can I make this work
}
}
所以我的问题是:
如何在编写函数时利用
我很感激学习资源并为我指明正确的方向。
I don't understand why the
output_iterator
takes a type butinput_iterator
doesn't any.
因为输入迭代器具有具体类型:它是您从 *it
获得的类型。那就是迭代器的引用类型(iter_reference_t<I>
).
但输出迭代器没有 - 它们只有一组类型,您可以写入它们。 *out
给你什么并不重要,重要的是你可以将什么类型放入 *out = x;
你不能要求像...给我所有可能的类型,你可以写进我的预期输出迭代器类型,O
。但是您可以询问 O
是否接受 specific 类型 T
.
例如,int*
是一个输入迭代器,其引用类型为 int&
。但是 int*
也可以用作输出迭代器 - 但适用于多种类型。 int
当然,还有 int16_t
,或 uint64_t
,或 char
,或任何其他可转换为 int
.
因此,您可以询问 I
是否是 input_iterator
,但您只能询问 O
是否是您正在写入的某些类型的 output_iterator
它 T
.
让我们来看看你的 random_assign
:
template<typename T, std::input_iterator InputIter, std::output_iterator<T> OutputIter>
requires std::random_access_iterator<InputIter>
auto random_assign(InputIter inputBegin, InputIter inputEnd, OutputIter outBegin);
首先,random_access_iterator
优化了 input_iterator
,因此您无需同时编写两者。只需选择最具体的约束。一旦你这样做了,你写入 outBegin
的类型就是你的输入迭代器的引用类型,所以这就是你需要的约束:
template <std::random_access_iterator I, std::output_iterator<std::iter_reference_t<I>> O>
void random_assign(I first, I last, O out);
接下来,您想要return有用的信息。在这种情况下,我们要前进 out
很多次,所以我们应该 return 它的新值。
全部内容:
template <std::random_access_iterator I, std::output_iterator<std::iter_reference_t<I>> O>
auto random_assign(I first, I last, O out) -> O {
// you can use distance, but we know it's random access
size_t const dist = last - first;
for (size_t i = 0; i != dist; ++i) {
// output_iterator requires this work
*out++ = first[rand() % dist];
}
// law of useful return
return out;
}