sfinae для обнаружения контейнеров: сбой для std:array

Я ищу способ использовать SFINAE для реализации некоторой функции, которая должна быть доступна только для некоторых контейнеров: вектор, список, массив (установлено ниже только в качестве теста)

Основываясь на этом ответе, я попробовал приведенный ниже код, в котором используется класс признаков, возвращающий true только для необходимых контейнеров.

Как вы можете видеть здесь, это не удается для std::array.

template <typename Container>
struct is_container : std::false_type { };

template <typename... Ts> struct is_container<std::array<Ts... >> : std::true_type { };
template <typename... Ts> struct is_container<std::vector<Ts...>> : std::true_type { };
template <typename... Ts> struct is_container<std::set<Ts...   >> : std::true_type { };
template <typename... Ts> struct is_container<std::list<Ts...  >> : std::true_type { };
template <typename... Ts> struct Dummy{};

int main()
{
    std::cout << "Dummy: " << is_container<Dummy<int>>::value << '\n';
    std::cout << "array: " << is_container<std::array<int,5>>::value << '\n';
    std::cout << "vector:" << is_container<std::vector<int>>::value << '\n';
    std::cout << "set: "   << is_container<std::set<int>>::value << '\n';
    std::cout << "list: "  << is_container<std::list<int>>::value << '\n';
}

Насколько я понимаю, это связано с тем, что std::array требует второго параметра шаблона. У меня мало опыта работы с вариативными шаблонами, поэтому мой вопрос:

Есть ли способ сделать этот подход успешным? Или мне следует использовать другой подход, описанный в связанном вопросе?

Я бы предпочел что-то чистое C++11, но C++14 тоже подойдет.


person kebs    schedule 23.06.2021    source источник
comment
Проблема в том, что второй параметр шаблона — это не тип, а число. Так что специализация не подходит.   -  person ALX23z    schedule 23.06.2021
comment
я собирался добавить тег c++11, но он был перемежен с другим редактированием, которое уже добавило максимум 5 тегов. Имхо, было бы неплохо иметь тег c++11, но не хотелось решать, что еще удалить   -  person 463035818_is_not_a_number    schedule 23.06.2021


Ответы (2)


Это не SFINAE, а обычная специализация шаблона. Ваш std::array не распознан, потому что значение типа std::size_t (которое является вторым аргументом std::array) не имя типа.

Вы можете специально изменить свою проверку для массива:

template <typename T, std::size_t N> struct is_container<std::array<T,N>> : std::true_type { };
template <typename... Ts> struct is_container<std::vector<Ts...>> : std::true_type { };

Если вы действительно хотите использовать SFINAE для проверки всего, что ведет себя как контейнер , вы можете проверить наличие std::begin, std::end, std::size для этого типа.

person bitmask    schedule 23.06.2021
comment
Извините, если это было неясно, я имел в виду, что это будет использоваться в какой-то функции шаблона Sfinae. - person kebs; 23.06.2021
comment
@кебс я вижу. Ну, на самом деле вы могли бы разрешить более общий тест, если вы проверяете свойства контейнера, а не явно перечисляете контейнер. Что, если ваш пользователь решит использовать std::unordered_set вместо std::set или std::deque вместо std::list. Или нестандартный контейнер, или... - person bitmask; 23.06.2021
comment
Смысл в том, чтобы разрешить коду функции только 3 перечисленных контейнера. Для std::set идея состоит в том, чтобы позволить сборке завершиться ошибкой. - person kebs; 23.06.2021
comment
Ах. В этом случае вы можете изменить установленную строку на template <typename... Ts> struct is_container<std::set<Ts... >> : std::false_type { }; или просто полностью удалить эту строку, потому что у вас есть значение по умолчанию, которое соответствует false_type. - person bitmask; 23.06.2021
comment
Конечно, да. Это было там просто как испытание. Или, лучше, я просто удалю эту строку. - person kebs; 23.06.2021
comment
Значит, это отвечает на ваш вопрос? - person bitmask; 23.06.2021
comment
Да, два ответа в основном одинаковы, обычно, когда это происходит, я принимаю ответ от самого низкого представителя ;-) Спасибо. - person kebs; 23.06.2021

Проблема в том, что второй параметр шаблона std::array не является параметром шаблона типа, который не соответствует пакету параметров шаблона типа typename... Ts.

Вы можете изменить специализацию для std::array на:

template <typename T, std::size_t S> struct is_container<std::array<T, S>> : std::true_type { };
person songyuanyao    schedule 23.06.2021