шаблон шаблон variadi c пакет параметров - PullRequest
1 голос
/ 13 января 2020

Может кто-нибудь объяснить приведенный ниже код пакетами параметров шаблона. Как это работает? Как упаковываются и распаковываются параметры шаблона в этом случае:

template<typename Test, template<typename...> class Ref> //#6
struct is_specialization : std::false_type {};

template<template<typename...> class Ref, typename... Args> //#7
struct is_specialization<Ref<Args...>, Ref>: std::true_type {};

Возможное запрошенное использование (на основе Перегрузка или специализация шаблона функции для внутреннего типа шаблона std :: vector )

template <typename T>
bool f(T& x) // #1
{
    std::cout << "body of f\n";
    return f(x);
}

template <typename T>
bool f(std::vector<T>& v) // #2
{
    std::cout << "body of f for vectors\n";
    return true;
}

template<typename T>
typename std::enable_if<
    is_specialization<typename T::value, std::vector>::value, T>::type
bool f(std::vector<T>& v) // #5
{
    std::cout << "body of f for vectors<vectors>\n";
    return true;
}

int main() {
  std::vector<int> v{1,2}
  f(v); 
}

1 Ответ

3 голосов
/ 14 января 2020

Ниже приведены некоторые пояснения по variadi c шаблонам синтаксису, упаковке и распаковке - о конкретном c рассматриваемом коде и о том, как заставить его работать 1 .


Кажется, что вы хотите добиться, чтобы провести различие между std::vector<int> и std::vector<float>.

Однако

Ваша функция # 1 слишком жадная и будет принимать все возможные аргументы:

template <typename T>
bool f(T& x) // #1
{
    std::cout << "body of f\n";
    return f(x);
}

, что может привести к неоднозначности, если какой-либо вызов подходит и к одной из перегруженных версий.

Итак, сначала нам нужно:

Разделить между is_vector или нет

Мы можем добиться этого с помощью следующего кода:

// [A]
template <class, template <class...> class>
struct is_of_template_type : std::false_type {};

// [B]
template <class T, class... Args, template <class...> class U>
struct is_of_template_type<U<T, Args...>, U> : std::true_type {};

// [C]
template <class Something>
struct is_vector: is_of_template_type<Something, std::vector> {};

[A] - базовый шаблон (не имеет ничего общего с наследованием) для случая generi c, перед какой-либо специализацией, для разрешения проверить, является ли данный тип заданным шаблоном c. Аргументы этого шаблона: (a) некоторый тип (b) некоторый другой тип, который должен быть шаблоном, с некоторыми неизвестными аргументами шаблона.

[B] является специализацией для true дело. Вызывающая сторона должна предоставить два параметра шаблона, но она будет соответствовать этой специализации, только если первый параметр шаблона соответствует типу шаблона, указанному в качестве второго параметра шаблона. Обратите внимание, что выражение ожидает два параметра шаблона: (a) аргумент шаблона U<T, Args...>, из которого мы будем выводить типы T и Args, и (b) другой аргумент шаблона - который должен быть аргументом шаблона из-за базовый шаблон - для которого мы игнорируем внутренние аргументы шаблона, так как нам просто нужно, чтобы первый тип соответствовал второму, независимо от внутренних аргументов шаблона.

[C] - это конкретное использование c для проверка, является ли данный тип vector, без необходимости иметь дело с параметрами шаблона вектора.


Теперь мы можем переписать function # 1 в:

template<typename Something>
typename std::enable_if<!is_vector<Something>::value>::type
f(const Something& v) // #1
{
    std::cout << "body of f for generic Something\n";
}

и он не такой жадный, как раньше, поскольку он требует только не-векторов.


Теперь мы готовы к нашей следующей задаче:

Разделение между различными видами векторов, то есть is_vector_of_T

Чтобы достичь этого, мы добавили бы следующее:

template <typename Container, typename T>
struct is_vector_of_T: std::false_type {};

template <typename T>
struct is_vector_of_T<std::vector<T>, T>: std::true_type {};

и теперь мы можем иметь отдельные функции для std::vector<int> и std::vector<float>:

template<typename Something>
typename std::enable_if<is_vector_of_T<Something, int>::value>::type
f(const Something& v) // #2
{
    std::cout << "body of f for vector<int>\n";
}

template<typename Something>
typename std::enable_if<is_vector_of_T<Something, float>::value>::type
f(const Something& v) // #3
{
    std::cout << "body of f for vector<float>\n";
}

Можем ли мы использовать его для выделения std::vector<std::vector<int>>? ​​* 1 079 * Да, мы можем: template<typename Something> typename std::enable_if<is_vector_of_T<Something, std::vector<int>>::value>::type f(const Something& v) // #4 { std::cout << "body of f for vector<vector<int>>\n"; } template<typename Something> typename std::enable_if<is_vector_of_T<Something, std::vector<float>>::value>::type f(const Something& v) // #5 { std::cout << "body of f for vector<vector<float>>\n"; } Код: https://godbolt.org/z/EFeGZk Примечания: Я использую enable_if во всех случаях выше, чтобы объявить возвращаемое значение метода как void или как несуществующее (SFINAE), это обычное использование мы вместо того, чтобы перегружать шаблонные функции для специализации шаблонных классов, может потребоваться enable_if с C ++ 20, мы бы заменили использование enable_if на requires синтаксис Другие соответствующие вопросы SO: Как определить, является ли тип шаблона экземпляром шаблона класс? Определить, является ли тип контейнером STL во время компиляции 1 Если упаковка и распаковка шаблонов variadi c совершенно нова для вас, я бы посоветовал начать изучать эту топи c с еще нескольких базовых c примеров, подобных это или т его . Этот вопрос конкретно относится к template template parameter (дубликат template не является ошибкой), который является более продвинутой топи c, вы можете следовать этому в качестве хорошей справки , Тогда вопрос более конкретно относится к variadic template template parameter, связанному с примерами, такими как this и this .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...