Reputation: 37
I have two functions, which accept variadic template, and second that accepts std::vector<std::string>. Is it possible, to override variadic templated function without additional arguments? I tried a few things, but it didn't work.
template <typename ... Args>
std::string Func(std::string, Args && ...);
template <typename ArgType = std::string, typename Alloc>
std::string Func(std::string, const std::vector<ArgType, Alloc> &);
int main()
{
std::vector<std::string> v;
Func("asd", 1, 2.0f);
Func("asd", v);
}
Always function with variadic template pack is called. Is the compiler really can't determine the vector specialization? Thanks
Upvotes: 2
Views: 1504
Reputation: 117228
Is the compiler really can't determine the vector specialization?
Yes it can, but it would require a conversion to const std::vector<ArgType, Alloc>&
so the first one that doesn't require any conversion is selected instead. If you remove the const
part it would select the second version.
You could create a type trait to disqualify the first function if the type is some sort of vector
though.
Example:
template<class... Ts>
struct is_first_a_vector {
static std::false_type test(...); // matches anything
// this matches only if the first argument is a `vector` of some sort:
template<template<class,class> class C, class T, class A, class... Rest>
static auto test(C<T,A>&&, Rest&&...) ->
std::enable_if_t<std::is_same_v<C<T,A>, std::vector<T,A>>, std::true_type>;
static constexpr bool value =
decltype(test(std::declval<std::remove_cvref_t<Ts>>()...))::value;
};
Alternatively:
template <class...>
struct is_first_a_vector_impl : std::false_type {};
template <class T, class A, class... Ts>
struct is_first_a_vector_impl<std::vector<T, A>, Ts...> : std::true_type {};
template <class... Ts>
struct is_first_a_vector
: is_first_a_vector_impl<std::remove_cv_t<std::remove_reference_t<Ts>>...> {};
Plus a helper that works with both type traits above:
template<class... Ts>
inline constexpr bool is_first_a_vector_v = is_first_a_vector<Ts...>::value;
And here's the type trait used to enable the first function only if the first argument after the std::string
is not a vector
of some sort:
template <typename... Args>
std::enable_if_t<!is_first_a_vector_v<Args...>, std::string> // <-
Func(std::string, Args&&...);
template <typename ArgType = std::string, typename Alloc>
std::string Func(std::string, const std::vector<ArgType, Alloc> &);
Demo using version 1 and Demo using version 2
Upvotes: 2