It's probably easiest to describe specifically what I'm trying to solve to make this easier to understand.
I have a SmartPointer
concept, so that I can have functions which can accept either std::unique_ptr
or std::shared_ptr
:
template <typename T>
concept SmartPointer = requires(const T& t) {
requires std::same_as<decltype(t.get()), typename T::pointer>;
};
I want to make a function which can take a pair of iterators, where the iterator value type must be of type SmartPointer
and I don't need to explicitly define any types.
I can create a function which has template parameter with the SmartPointer constraint, and check against that:
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.
}
}
However, when using it, I am required to explicitly specify T
, which I would prefer not to have to do:
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
From the error message, I'm guessing I need some sort of template deduction guide but as far as I can see they can only be defined for classes/structs and not functions.
I essentially want something like this:
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.
}
}
Am I going about this in the correct way? Is this even possible? Thank you in advance!
CodePudding user response:
You don't need T
as a template parameter:
template < std::forward_iterator TIterator
, std::sentinel_for<TIterator> TIteratorSentinel >
requires SmartPointer< std::iter_value_t<TIterator> >
// ^^^^^^^^^^^^
void whatever(TIterator begin, TIteratorSentinel end)
{
// ...
}
CodePudding user response:
If you have lot's of functions templated like whatever
, it might be worth defining a concept for "iterator pointing to smart pointer"
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)
{
// ...
}