如何用另一个概念来表达约束

How to express a constraint in terms of another concept

具体描述我要解决的问题可能是最简单的方法,这样更容易理解。

我有一个 SmartPointer 概念,因此我可以拥有可以接受 std::unique_ptrstd::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)
{
    // ...
}