Ответ 1
Функция С++ 14, переопределенная:
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;
Библиотека мини-метапрограммирования:
template<class...>struct types{using type=types;};
namespace details {
template<template<class...>class Z, class types, class=void>
struct can_apply : std::false_type {};
template<template<class...>class Z, class...Ts>
struct can_apply< Z, types<Ts...>, void_t< Z<Ts...> > >:
std::true_type
{};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z,types<Ts...>>;
can_apply< some_template, args... >
наследует от true_type
iff some_template<args...>
- допустимое выражение (в непосредственном контексте).
Теперь для вашей проблемы:
template<class T, class I>
using dot_count_type = decltype( std::declval<T>().count(std::declval<I>()) );
template<class T, class I>
using has_dot_count = can_apply<dot_count_type, T, I>;
и has_dot_count
- класс признаков, который наследует от true_type
iff T.count(I)
- допустимое выражение.
namespace details {
template<class C, class I>
bool contains(std::false_type, C const& c, I const& i) {
for(auto&& x:c) {
if(x == i) { return true; }
}
return false;
}
template<class C, class I>
bool contains(std::true_type, C const& c, I const& i) {
return c.count(i) != 0;
}
}
template<class C, class I>
bool contains( C const& c, I const& i ) {
return details::contains( has_dot_count<C const&,I const&>{}, c, i );
}
который использует диспетчеризацию меток вместо SFINAE.
Использование find
кажется лучшей идеей, чем .count
как сторонняя. Фактически, в одном случае вы должны использовать .find
другой find
. В обоих случаях вы должны использовать using std::end; auto e = end(c);
.
Как в стороне, MSVC 2013 (я не знаю о 2015) не обрабатывает этот вид SFINAE, использованный выше. Они называют это "выражением SFINAE". У них есть пользовательские расширения для обнаружения существования функции-члена. Но это потому, что они далеки от совместимого с С++ 11.