I have two overloads:
template<typename... T>
void f(T&&... args);
template<typename ContainerType>
void f(const ContainerType& container);
how can I make it choose the second overload if called as e.g.
f(std::vector());
(or any other type that has e.g. begin()
method)
An rvalue reference binding to an rvalue is "better" than a const lvalue reference binding to an lvalue. So you need to make both bindings equally good by changing the second overload to also take a forwarding reference:
template <typename ContainerType>
void f(ContainerType&& container);
Now, if both overloads are viable, the non-variadic one will be selected because it is "more specialized". (The "more specialized" tiebreaker is only applied if both overloads are equally good for every argument in the call.)
If you also want to constrain it so that container.begin()
must be well-formed, you can do so in C++17 as follows:
template <typename ContainerType>
auto f(ContainerType&& container) -> std::void_t<decltype(container.begin())>;
Now, this overload will be selected if there is a single argument and the constraint is satisfied. If either condition doesn't hold, the variadic overload will be selected.
(To be really pedantic, you might want to use static_cast<ContainerType&&>(container).begin()
to do perfect forwarding inside the decltype
specifier.)