如何用另一个概念来表达约束
How to express a constraint in terms of another concept
具体描述我要解决的问题可能是最简单的方法,这样更容易理解。
我有一个 SmartPointer
概念,因此我可以拥有可以接受 std::unique_ptr
或 std::shared_ptr
的函数:
template <typename T>
concept SmartPointer = requires(const T& t) {
requires std::same_as<decltype(t.get()), typename T::pointer>;
};
我想创建一个可以接受一对迭代器的函数,其中迭代器值类型必须是 SmartPointer
类型,我不需要显式定义任何类型。
我可以创建一个具有带有 SmartPointer 约束的模板参数的函数,并检查它:
template <SmartPointer T, std::forward_iterator TIterator, std::sentinel_for<TIterator> TIteratorSentinel>
requires std::same_as<std::iter_value_t<TIterator>, T>
void doWithSmartPointers(TIterator begin, TIteratorSentinel end) {
for (auto it = begin; it != end; ++it) {
// Some logic with it->get() etc.
}
}
但是,在使用它时,我需要明确指定 T
,我不想这样做:
std::vector<std::unique_ptr<int>> v{};
v.push_back(std::make_unique<int>(1));
v.push_back(std::make_unique<int>(2));
v.push_back(std::make_unique<int>(3));
doWithSmartPointer(v.begin(), v.end()); // Error, couldn't infer template argument T
doWithSmartPoint<std::unique_ptr<int>>(v.begin(), v.end()); // OK
根据错误消息,我猜我需要某种模板推导指南,但据我所知,它们只能为 classes/structs 而不是函数定义。
我基本上想要这样的东西:
template <std::forward_iterator TIterator, std::sentinel_for<TIterator> TIteratorSentinel>
requires std::same_as<std::iter_value_t<TIterator>, SmartPointer> // Not valid syntax!
void doWithSmartPointers(TIterator begin, TIteratorSentinel end) {
for (auto it = begin; it != end; ++it) {
// Some logic with it->get() etc.
}
}
我的处理方式是否正确?这可能吗?提前致谢!
您不需要 T
作为模板参数:
template < std::forward_iterator TIterator
, std::sentinel_for<TIterator> TIteratorSentinel >
requires SmartPointer< std::iter_value_t<TIterator> >
// ^^^^^^^^^^^^
void whatever(TIterator begin, TIteratorSentinel end)
{
// ...
}
如果您有很多像 whatever
这样模板化的函数,可能值得为“指向智能指针的迭代器”定义一个概念
template <typename T>
concept SmartPointerIterator = requires std::forward_iterator<T> && SmartPointer<std::iter_value_t<T>>;
template < SmartPointerIterator TIterator
, std::sentinel_for<TIterator> TIteratorSentinel >
void whatever(TIterator begin, TIteratorSentinel end)
{
// ...
}
具体描述我要解决的问题可能是最简单的方法,这样更容易理解。
我有一个 SmartPointer
概念,因此我可以拥有可以接受 std::unique_ptr
或 std::shared_ptr
的函数:
template <typename T>
concept SmartPointer = requires(const T& t) {
requires std::same_as<decltype(t.get()), typename T::pointer>;
};
我想创建一个可以接受一对迭代器的函数,其中迭代器值类型必须是 SmartPointer
类型,我不需要显式定义任何类型。
我可以创建一个具有带有 SmartPointer 约束的模板参数的函数,并检查它:
template <SmartPointer T, std::forward_iterator TIterator, std::sentinel_for<TIterator> TIteratorSentinel>
requires std::same_as<std::iter_value_t<TIterator>, T>
void doWithSmartPointers(TIterator begin, TIteratorSentinel end) {
for (auto it = begin; it != end; ++it) {
// Some logic with it->get() etc.
}
}
但是,在使用它时,我需要明确指定 T
,我不想这样做:
std::vector<std::unique_ptr<int>> v{};
v.push_back(std::make_unique<int>(1));
v.push_back(std::make_unique<int>(2));
v.push_back(std::make_unique<int>(3));
doWithSmartPointer(v.begin(), v.end()); // Error, couldn't infer template argument T
doWithSmartPoint<std::unique_ptr<int>>(v.begin(), v.end()); // OK
根据错误消息,我猜我需要某种模板推导指南,但据我所知,它们只能为 classes/structs 而不是函数定义。
我基本上想要这样的东西:
template <std::forward_iterator TIterator, std::sentinel_for<TIterator> TIteratorSentinel>
requires std::same_as<std::iter_value_t<TIterator>, SmartPointer> // Not valid syntax!
void doWithSmartPointers(TIterator begin, TIteratorSentinel end) {
for (auto it = begin; it != end; ++it) {
// Some logic with it->get() etc.
}
}
我的处理方式是否正确?这可能吗?提前致谢!
您不需要 T
作为模板参数:
template < std::forward_iterator TIterator
, std::sentinel_for<TIterator> TIteratorSentinel >
requires SmartPointer< std::iter_value_t<TIterator> >
// ^^^^^^^^^^^^
void whatever(TIterator begin, TIteratorSentinel end)
{
// ...
}
如果您有很多像 whatever
这样模板化的函数,可能值得为“指向智能指针的迭代器”定义一个概念
template <typename T>
concept SmartPointerIterator = requires std::forward_iterator<T> && SmartPointer<std::iter_value_t<T>>;
template < SmartPointerIterator TIterator
, std::sentinel_for<TIterator> TIteratorSentinel >
void whatever(TIterator begin, TIteratorSentinel end)
{
// ...
}