my_fun può essere implementata come segue usando 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));
}
nota il passaggio di un puntatore classe Base
o Derived
qui, altrimenti compilatore si lamentano definizione della funzione ambigua.
Il compilatore cercherà di abbinare la firma esatta di my_fun_impl
con B pointer
, riuscirà in caso di contenitore. Perché un container avrà begin() e end(), previsto nel tipo di ritorno finale.
In caso di tipo non contenitore, la prima opzione non corrisponde. E come sappiamo che un puntatore della classe Base
può contenere un oggetto classe derivato, quindi la corrispondenza predefinita avrà esito positivo.
e di uscita del seguente codice di prova
int main()
{
my_fun(std::vector<int>{1,2,3});
my_fun(1);
}
sarà
Container
Other than Container
Demo on coliru
Oltre a guardare come una cattiva progettazione e mi raccomandando comunque di leggere il disegno, invece, è possibile utilizzare [ * Tipo-tratti *] (http://en.cppreference.com/w/cpp/types#Type_traits_.28since_C.2B.2B11.29). Potrebbe essere necessario implementare specifici tratti del tipo che ti si addicono, come "is_container". –
'std :: string' è ovviamente un contenitore di caratteri, quindi questa domanda presuppone una falsa dicotomia. – MSalters