my_fun can be implemented as following using SFINAE.
namespace details{
struct A{};
struct B:A{};
// A container will have a begin and an end. Also make it first prerference
template<typename T>
auto my_fun_impl(T const & obj, B *) -> decltype( obj.begin(),obj.end(),void())
{
std::cout<<"Container\n";
}
// Default choice
template<typename T>
auto my_fun_impl(T const & obj,A*) -> void
{
std::cout<<"Other than Container\n";
}
}
template<typename T>
auto my_fun(T const & obj) -> void
{
details::my_fun_impl(obj,static_cast<details::B *>(0));
}
Note the passing a Base
or Derived
class pointer here, otherwise compiler will complain about ambiguous function definition.
Compiler will try to match exact signature of my_fun_impl
with B pointer
, it will succeed in case of container. Because a container will have begin() and end(), expected in trailing return type.
In case of non-container type first option will fail to match. And as we know that a Base
class pointer can hold a derived class object, so default match will succeed.
And output of following test code
int main()
{
my_fun(std::vector<int>{1,2,3});
my_fun(1);
}
will be
Container
Other than Container
Demo on coliru