简体   繁体   English

模板模板可变参数包

[英]template template variadic parameter pack

Can someone please explain the below code with template parameter packs.有人可以用模板参数包解释下面的代码吗? How does it work?它是如何工作的? How are the template parameters packed and unpacked in this case:这种情况下模板参数是如何打包和解包的:

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 {};

Possible requested usage (inspired by Function Template Overloading or Specialization for inner template type std::vector<std::vector<T>> )可能的请求用法(受内部模板类型 std::vector<std::vector<T>>函数模板重载或特化启发)

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); 
}

Below are some explanations on variadic templates syntax, packing and unpacking -- on the specific code in question and how to make it work 1 .下面是关于可变参数模板语法、打包和解包的一些解释——关于有问题的特定代码以及如何使其工作1


It seems that what you want to achieve is to differentiate between std::vector<int> and std::vector<float> .似乎您想要实现的是区分std::vector<int>std::vector<float>

However然而

Your function #1 is too greedy and would take all possible arguments:你的函数 #1太贪婪了,会接受所有可能的参数:

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

which would result with ambiguity if any call fits also one of the overloaded versions.如果任何调用也适合重载版本之一,则会导致歧义。

So, we first need to:所以,我们首先需要:

Separate between is_vector or not是否在is_vector之间is_vector

We can achieve that with the following code:我们可以通过以下代码实现:

// [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] is the base template (nothing to do with inheritance) for the generic case, before any specialization, for allowing to test if a given type is a specific template. [A] 是泛型案例的基本模板(与继承无关),在任何特化之前,用于允许测试给定类型是否是特定模板。 This template arguments are: (a) some type (b) some other type that must be a template, with some unknown template arguments.这个模板参数是: (a) 某种类型 (b) 某种其他类型,它必须是一个模板,带有一些未知的模板参数。

[B] is the specialization for the true case. [B]是对专业化true情况。 The caller should provide two template parameters but it would fit this specialization only if the first template parameter fits the template type given as the second template parameter.调用者应提供两个模板参数,但仅当第一个模板参数适合作为第二个模板参数给出的模板类型时,它才适合此特化。 Note that the expression expects two template parameters: (a) a template argument U<T, Args...> from which we will infer the types T and Args , and (b) another template argument -- which must be a template argument because of the base template -- for which we ignore the inner template arguments, as we just need the first type to match the second, regardless of the inner template arguments.请注意,表达式需要两个模板参数:(a) 一个模板参数U<T, Args...> ,我们将从中推断出TArgs类型,以及 (b) 另一个模板参数——它必须是一个模板参数因为基本模板——我们忽略了内部模板参数,因为我们只需要第一个类型来匹配第二个类型,而不管内部模板参数如何。

[C] is the specific usage for checking if a given type is a vector , without the need to deal with the vector template parameters. [C] 是检查给定类型是否为vector的具体用法,无需处理向量模板参数。


Now we can rewrite function #1 to:现在我们可以将函数#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";
}

and it is not so greedy as before, as it takes only non-vectors.它不像以前那么贪婪,因为它只需要非向量。


Now we are ready for our next task:现在我们准备好我们的下一个任务:

Separate between different kind of vectors, ie is_vector_of_T不同类型的向量之间分开,即is_vector_of_T

To achieve that we would add the following:为了实现这一点,我们将添加以下内容:

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 {};

and now we can have separate functions for std::vector<int> and std::vector<float> :现在我们可以为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";
}

Can we use it to isolate std::vector<std::vector<int>> ?我们可以用它来隔离std::vector<std::vector<int>>吗?

Yes we can:我们可以:

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";
}

Code: https://godbolt.org/z/EFeGZk代码: https : //godbolt.org/z/EFeGZk


Notes:笔记:

  • I use enable_if in all cases above to declare the return value of the method as void or as non-existing (SFINAE), this is a common use我在上述所有情况下都使用enable_if将方法的返回值声明为void或不存在(SFINAE),这是一个常见用途

  • we may consider instead of overloading template functions to specialize template classes, it may reduce the need of enable_if我们可以考虑代替重载模板函数来专门化模板类,它可能会减少对enable_if的需求

  • with C++20 we would replace the use of enable_if with the requires syntax在 C++20 中,我们将使用requires语法替换enable_if的使用


Other relevant SO questions:其他相关的 SO 问题:


1 If variadic templates packing and unpacking is entirely new to you I would suggest starting to learn this topic from some more basic examples like this or this . 1如果可变参数模板打包和解包对您来说是全新的,我建议您从一些更基本的例子开始学习这个主题,比如 这个这个 The question is specifically related to template template parameter (the duplicate template is not a mistake) which is a more advanced topic, you can follow this as a good reference.该问题具体与template template parameter (重复template不是错误),这是一个更高级的主题,您可以将作为一个很好的参考。 Then, the question is more specifically related to variadic template template parameter , related to examples like this and this .然后,问题是更具体涉及variadic template template parameter ,涉及到像例子这个这个

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM