如何用Concepts约束std::input_iterator的值类型为bar?
用C++ Concepts约束迭代器指向bar类型
问题描述
现有如下C++代码:
#include <iterator> #include <vector> struct bar{}; struct details {}; struct foo { details det; std::vector<bar> data; }; template <std::input_iterator Iter> foo create_foo(const details& details, Iter begin, Iter end) { return foo { .det = details, .data = {begin, end} }; } int main() { std::vector<bar> bars = {bar{},bar{},bar{}}; create_foo({}, bars.begin(), bars.end()); return 0; }
需求:foo::data是bar类型的容器,其构造函数接受两个迭代器。需要将输入迭代器约束为仅指向bar类型元素的迭代器(如std::vector<bar>::iterator或std::list<bar>::iterator),询问如何通过C++20 Concepts实现该约束。
解决方案
方法1:自定义Concept约束
先定义一个Concept,同时满足两个条件:迭代器是std::input_iterator,且其指向的元素类型为bar:
#include <iterator> #include <vector> #include <list> #include <concepts> struct bar{}; struct details {}; struct foo { details det; std::vector<bar> data; }; // 自定义Concept:指向bar的输入迭代器 template <typename Iter> concept BarInputIterator = std::input_iterator<Iter> && std::same_as<typename std::iterator_traits<Iter>::value_type, bar>; // 使用Concept约束模板参数 template <BarInputIterator Iter> foo create_foo(const details& details, Iter begin, Iter end) { return foo { .det = details, .data = {begin, end} }; } int main() { std::vector<bar> bars = {bar{},bar{},bar{}}; create_foo({}, bars.begin(), bars.end()); // 合法,符合约束 std::list<bar> bar_list = {bar{}, bar{}}; create_foo({}, bar_list.begin(), bar_list.end()); // 合法,符合约束 // std::vector<int> ints = {1,2,3}; // create_foo({}, ints.begin(), ints.end()); // 编译错误:违反Concept约束 return 0; }
方法2:内嵌约束(无需自定义Concept)
如果不需要复用这个约束,可以直接在模板参数后通过requires子句添加条件:
#include <iterator> #include <vector> #include <concepts> struct bar{}; struct details {}; struct foo { details det; std::vector<bar> data; }; template <std::input_iterator Iter> requires std::same_as<typename std::iterator_traits<Iter>::value_type, bar> foo create_foo(const details& details, Iter begin, Iter end) { return foo { .det = details, .data = {begin, end} }; } int main() { std::vector<bar> bars = {bar{},bar{},bar{}}; create_foo({}, bars.begin(), bars.end()); return 0; }
关键说明
std::iterator_traits<Iter>::value_type用于获取迭代器Iter指向的元素类型;std::same_as保证元素类型与bar严格匹配,如果需要支持可隐式转换为bar的类型,可以替换为std::convertible_to<typename std::iterator_traits<Iter>::value_type, bar>,但根据需求,严格匹配更合适;- 当传入不符合约束的迭代器时,编译器会直接抛出错误,阻止模板实例化,实现类型安全。
内容的提问来源于stack exchange,提问作者user3001150
相关产品推荐
相关产品推荐

