Given this template function:
template <
typename T,
typename U,
typename = std::enable_if<
std::is_same_v<U, std::unique_ptr<T>> ||
std::is_same_v<U, std::shared_ptr<T>>>>
T foo(U val) {
if constexpr (std::is_same_v<U, std::unique_ptr<T>>) {
return *val;
}
return *val;
}
I want to call it like this:
int x = foo(std::make_unique<int>(1));
But, it's giving this error:
Candidate template ignored: couldn't infer template argument 'T'
I can fix it by providing the type T explicitly:
int x = foo<int>(std::make_unique<int>(1));
Is it possible to fix it such that it can infer? The type is clearly embedded in the typename U
but it does not seem to "propagate" to T
.
CodePudding user response:
SFINAE constraints don't affect template argument deduction. Your compiler has to deduce T
and U
first, without even looking at your enable_if_t<...>
.
I'd do something like this:
#include <memory>
#include <type_traits>
namespace impl
{
template <typename A, template <typename...> typename B>
struct specialization_of : std::false_type {};
template <template <typename...> typename T, typename ...P>
struct specialization_of<T<P...>, T> : std::true_type {};
}
template <typename A, template <typename...> typename B>
concept specialization_of = impl::specialization_of<A, B>::value;
template <typename T>
requires specialization_of<T, std::unique_ptr> || specialization_of<T, std::shared_ptr>
auto foo(T val)
{
if constexpr (specialization_of<T, std::unique_ptr>)
{
return *val;
}
return *val;
}
[I also want]
std::is_same_v<U, std::function<T()>>
Then you need a specialized template just for this task. Something like:
template <typename T, typename U>
struct foo : std::false_type {};
template <typename T, typename U>
struct foo<std::function<T()>, U> : std::is_same<T, U> {};
Then foo<std::function<int()>, int>
is true.