我对概念和范围/观点很陌生。
我试图通过传递由迭代器或范围/视图定义的值序列来编写类的初始化。
我能够检查函数参数是迭代器还是范围。但我无法检查迭代器返回的值是否是特定类型。
例如(C++23):
#include <print>
#include <vector>
struct Data {
int i;
std::string l;
};
struct DataContainer {
// iterator version
// QUESTION: how can I check that I handles "Data"?
template<std::input_iterator I, std::sentinel_for<I> S>
void add(I start, S end) {
for (auto data = start; data != end; ++data) {
_data.push_back(*data);
}
}
// range/views version
// QUESTION: how can I check that R handles "Data"?
template<std::ranges::input_range R>
void add(R &&r) {
add(std::begin(r), std::end(r));
}
void dump() const {
for (const auto& d: _data){
std::print("[{},'{}'], ", d.i, d.l);
}
std::println();
}
std::vector<Data> _data;
};
int main()
{
std::vector<Data> init{{1, "one"}, {2, "two"}, {3, "three"}};
{
DataContainer dc;
dc.add(init.begin(), init.end());
dc.dump();
}
{
DataContainer dc;
dc.add(init);
dc.dump();
}
return 0;
}
如何检查
*start
是否返回 Data
?
在这两种情况下,您都可以添加约束:
template <std::input_iterator I, std::sentinel_for<I> S>
requires std::convertible_to<std::iter_value_t<I>, Data> // constraint added
void add(I start, S end) {
// ...
}
template <std::ranges::input_range R>
requires std::convertible_to<std::iter_value_t<R>, Data> // constraint added
void add(R&& r) {
// ...
}
std::convertible_to
:
概念
指定与convertible_to<From, To>
相同类型和值类别的表达式可以隐式和显式转换为类型std::declval<From>()
,并且两种形式的转换产生相同的结果。To
std::iter_value_t
- 计算
的值类型。T
- 如果
没有专门化,那么std::iterator_traits<std::remove_cvref_t<T>>
就是std::iter_value_t<T>
。std::indirectly_readable_traits<std::remove_cvref_t<T>>::value_type
- 否则就是
。std::iterator_traits<std::remove_cvref_t<T>>::value_type
std::constructible_from
代替 std::convertible_to
。