Как я могу заставить foo принимать только шаблоны только с двумя параметрами шаблона, поэтому он не работает с std :: map в C ++ 17?
Если вы хотите избежать этого foo()
принять контейнер, принимающий три или более параметров шаблона (поэтому не работает с std::map
), относительно просто: вы можете следовать предложению rtpax или, учитывая особенности пользовательского типа, которые говорят, основан ли тип на принимающем контейнере двух типов
template <typename>
struct accept2 : std::false_type
{ };
template <template <typename...> class C, typename X, typename Y>
struct accept2<C<X, Y>> : std::true_type
{ };
и признаки аналогичного типа для трехпринимающего контейнера
template <typename>
struct accept3 : std::false_type
{ };
template <template <typename...> class C, typename X, typename Y, typename Z>
struct accept3<C<X, Y, Z>> : std::true_type
{ };
Вы можете включить SFINAE foo()
, только если выведенный тип принимает два, но не принимает три типа
template <typename C>
std::enable_if_t<accept2<C>{} && !accept3<C>{}> foo (C const & container)
{ }
Но у этого решения (и также у rtpax) есть проблема: как насчет контейнера, который получает до двух типов шаблонов и после одного (или более) параметра не типового шаблона со значениями по умолчанию?
Или два типа шаблона и один (или более) параметр шаблона-шаблона со значениями по умолчанию?Может быть, с разными подписями?
Вы можете добавить специализации для accept3
, чтобы распознавать другие случаи, но есть бесконечные комбинации типа, нетипа и параметра шаблона-шаблона со значением по умолчанию после первых двух шаблонов.тип.Поэтому вам нужно написать бесконечную специализацию для перехвата всех случаев.
Это немного непрактично.
И я подозреваю, что (в C ++ 17) практического решения нет.
В любом случае, следует полный пример компиляции (исключая контейнеры трех или более типов шаблонов)
#include <map>
#include <vector>
#include <type_traits>
template <typename>
struct accept2 : std::false_type
{ };
template <template <typename...> class C, typename X, typename Y>
struct accept2<C<X, Y>> : std::true_type
{ };
template <typename>
struct accept3 : std::false_type
{ };
template <template <typename...> class C, typename X, typename Y, typename Z>
struct accept3<C<X, Y, Z>> : std::true_type
{ };
template <typename C>
std::enable_if_t<accept2<C>{} && !accept3<C>{}> foo (C const &)
{ }
int main()
{
std::vector<int> v;
std::map<int,int> m;
foo(v); // compile
//foo(m); // compilation error
}