I'm encountering an issue where the compiler seems unable to implicitly deduce the template argument T
when I try to call largest()
with a std::vector<T>
. Explicitly specifying T
(e.g., largest<std::string>(myVector)
) works, but I'm seeking a deeper understanding of why this is necessary.
std::string largest(std::span< std::string > elements);
template <typename T> std::optional<T> largest(std::span<T> elements);
int main(int argc, char* argv[]) {
std::vector< std::string > elements { "A", "B", "C", "D" };
std::cout << largest(elements) << std::endl;
std::vector<int> integers { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
// std::cout << largest(integers) << std::endl; COMPILER CAN'T RESOLVE OVERLOAD
// correct version
std::optional<int> maximum { largest<int>(integers) };
if(maximum.has_value())
std::cout << maximum.value() << std::endl;
return 0;
}
std::string largest(std::span< std::string > elements) {
std::string maximum {};
for(const auto& element : elements) {
if(auto ordering { element <=> maximum }; ordering == std::strong_ordering::greater)
maximum = element;
}
return maximum;
}
template <typename T> std::optional<T> largest(std::span<T> elements) {
if( elements.empty() ) return std::nullopt;
T maximum {};
for(const auto& element : elements) {
if(auto ordering { element <=> maximum }; ordering == std::strong_ordering::greater)
maximum = element;
}
return maximum;
}
the compiler seems unable to implicitly deduce the template argument
T
when I try to calllargest()
with astd::vector<T>
Yes, for it to be possible to deduce T
, you'd have to supply a std::span
over "something". The match must be exact for deduction to work and a vector<T>
and a span<T>
are not the same type and it doesn't help that a span<T>
has a converting constructor that lets it be created from a vector<T>
.
You could however make it simpler by just accepting any forward range. To simplify it further, you could also use a standard algorithm to find the element with the maximum value.
Example:
#include <algorithm>
#include <iterator>
#include <optional>
#include <ranges>
auto largest(std::ranges::forward_range auto&& elements) {
// get an iterator to the maximum element:
auto maxit = std::ranges::max_element(elements);
// create an empty optional with the correct value type:
std::optional<std::iter_value_t<decltype(maxit)>> maximum;
// if the range was not empty, assign the found value:
if (maxit != std::ranges::end(elements)) maximum = *maxit;
return maximum;
}