我们从一个例子来引入concepts:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<int> container{1, 5, 4, 3, 2};
std::ostream_iterator<int> out(std::cout, " ");
std::copy(std::begin(container), std::end(container), out);
std::cout<<"\n";
std::sort(std::begin(container), std::end(container));
std::copy(std::begin(container), std::end(container), out);
std::cout<<"\n";
return 0;
}
运行结果如下:
image.png
程序正确,得到了我们想要的结果。
现在我们修改一下容器的类型,改为std::list
。然后编译就出错了,而且错误信息很多,根本就没有办法知道错误到底是啥,需要在哪里修改。
然后你会一点一点的分析,最后找到了答案了:
迭代器分为五个类别(在C++20之前是5个,C++20增加了contiguous_iterator_tag
):
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : input_iterator_tag {};
struct bidirectional_iterator_tag : forward_iterator_tag {};
struct random_access_iterator_tag : bidirectional_iterator_tag {};
而std::sort
中的迭代器参数需要的是random_access_iterator_tag
。std::vector
的迭代器类型为random_access_iterator_tag
,而std::list
的迭代器类型为bidirectional_iterator_tag
,所以编译错误。
当我们找到问题的答案后,才发现这个问题的原因是如此的简单,但是编译器给出的错误信息确是如此的复杂且不知所以然。
这里的问题在于,对于std::sort
的参数是有限制的,不是说任何的迭代器都是可用的。为了明确编程中的一些限制,C++给出了concepts。
我们继续我们上面的例子,修改如下:
#include <concepts>
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <list>
template<typename T>
concept sortable = requires(T t, size_t i){t[i];};
template<sortable T>
void sort(T& t){
std::sort(std::begin(t), std::end(t));
}
int main()
{
std::vector<int> container{1, 5, 4, 3, 2};
std::ostream_iterator<int> out(std::cout, " ");
std::copy(std::begin(container), std::end(container), out);
std::cout<<"\n";
sort(container);
std::copy(std::begin(container), std::end(container), out);
std::cout<<"\n";
return 0;
}
这里我们增加了
template<typename T>
concept sortable = requires(T t, size_t i){t[i];};
意思是新增加了一种concept,也就是一种限制,将一个类型现定于有operator[]
成员函数。这里我们假设有这个成员函数的类型满足random_access_iterator_tag
迭代器。
然后我们声明了一个sort
函数:
template<sortable T>
void sort(T& t){
std::sort(std::begin(t), std::end(t));
}
告知调用者其参数类型应当满足sortable
这个限制。
然后我们将std::vector<int> container{1, 5, 4, 3, 2};
改为std::list<int> container{1, 5, 4, 3, 2};
,重新编译代码,得到下面的错误
这样看起来是不是容易理解多了。
网友评论