I can imagine the following code:
template class X
{
public:
T container;
void foo()
{
if(is_vector(T))
contain
Here's the typical method using void_t:
template
using void_t = void; // C++17 std::void_t
template // I'm using C for "container" instead of T, but whatever.
struct has_push_back_impl : std::false_type {};
template
struct has_push_back_impl().push_back(typename C::value_type{}))>>
: std::true_type {}; // Note that void_t is technically not needed in this case, since the 'push_back' member function actually returns void anyway, but it the general method to pass the type into void_t's template argument to obtain void. For example, the 'insert' function from std::set and std::map do NOT return void, so 'has_insert' will need to use void_t.
template
using has_push_back = has_push_back_impl; // void passed to the second template argument by default, thus allowing the second specialization to be used instead of the primary template whenever C has a push_back member function.
This method will work for has_insert for associative containers, even though std::set, std::map's insert function return std::pair while std::multimap::insert returns std::multimap::iterator (this is one case where Ze Blob's method will not work).