В некоторых версиях C ++ Container
не может соответствовать std::vector
, потому что std::vector
на самом деле не template <typename> class
. Это template <typename, typename> class
, где второй параметр (тип распределителя) имеет аргумент шаблона по умолчанию.
Хотя это может помочь добавить еще один параметр шаблона typename Alloc
, сделав параметр функции Container<std::pair<Iterator, Iterator>, Alloc>
, который может быть проблема для других типов контейнеров.
Но поскольку ваша функция на самом деле не использует параметр шаблона шаблона Container
, нет необходимости требовать такого сложного вывода аргумента шаблона со всеми хитростями и ограничениями вывода шаблон аргумента шаблона:
template<typename Iterator, class Container>
void foo(Iterator first, Container const &findings);
Для этого также не требуется вывод Iterator
как одного и того же типа в трех разных местах. Это означает, что будет допустимо передать X::iterator
как first
и контейнер, содержащий X::const_iterator
или наоборот, и вывод аргумента шаблона все еще может быть успешным.
Один небольшой недостаток заключается в том, что, если другой шаблон использует SFINAE пытается определить, действительна ли подпись foo
, эта декларация будет соответствовать почти чему угодно, например, foo(1.0, 2)
. Это часто не важно для специфической c -целевой функции, но приятно быть более ограничительным (или «дружественным по отношению к SFINAE»), по крайней мере, для функций общего назначения. Мы могли бы добавить базовое ограничение c что-то вроде:
// Require Container is container-like (including raw array or std::initializer_list)
// and its values have members first and second of the same type,
// which can be compared for equality with Iterator.
template <typename Iterator, class Container>
auto foo(Iterator first, Container const &findings)
-> std::void_t<decltype(first == std::begin(findings)->first),
std::enable_if_t<std::is_same_v<std::begin(findings)->first,
std::begin(findings)->second>>>;