【问题标题】:template template variadic parameter pack模板模板可变参数包
【发布时间】:2020-04-29 21:34:57
【问题描述】:

有人可以用模板参数包解释下面的代码吗? 它是如何工作的?这种情况下模板参数是如何打包和解包的:

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

可能的请求用法(灵感来自Function Template Overloading or Specialization for inner template type 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); 
}

【问题讨论】:

  • 我很困惑。 #2 应该无条件地绑定,因为这是这里的最佳匹配。 #5 甚至没有在这里发挥作用,不包括任何和所有 SFINAE。你到底有什么不清楚的地方?抛开#5 甚至不应该编译的问题,除非你的意思是template&lt;typename T, typename = std::enable_if&lt;is_specialization&lt;typename T::value, std::vector&gt;::value, T&gt;::type&gt;
  • @TanveerBadar:您能否参考给出的链接中的完整代码。我已对问题进行了编辑。请看一看。
  • @TechTotie 您到底需要澄清什么? is_specialization 定义的哪一部分你不明白?
  • @walnut 请让我知道#5 的工作原理以及 is_specialization 是如何工作的 w.r.t 模板参数打包和解包。

标签: c++ variadic-templates template-specialization parameter-pack


【解决方案1】:

以下是关于可变参数模板语法、打包解包 -- 关于有问题的特定代码以及如何使其工作1


看来你想要实现的是区分std::vector&lt;int&gt;std::vector&lt;float&gt;

然而

你的函数#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] 是通用案例的基本模板(与继承无关),在任何特化之前,允许测试给定类型是否是特定模板。该模板参数是:(a) 某种类型 (b) 必须是模板的某种其他类型,带有一些未知的模板参数。

[B] 是true 案例的专业化。调用者应该提供两个模板参数,但只有当第一个模板参数适合作为第二个模板参数给出的模板类型时,它才会适合这个特化。请注意,表达式需要两个模板参数:(a) 一个模板参数U&lt;T, Args...&gt;,我们将从中推断出类型TArgs,以及(b) 另一个模板参数——它必须是一个模板参数,因为基本模板——我们忽略了内部模板参数,因为我们只需要第一个类型来匹配第二个,而不管内部模板参数是什么。

[C]是检查给定类型是否为vector的具体用法,无需处理向量模板参数。


现在我们可以将函数#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&lt;int&gt;std::vector&lt;float&gt; 设置单独的函数:

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&lt;std::vector&lt;int&gt;&gt;吗?

是的,我们可以:

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 问题:


1如果可变参数模板打包和解包对您来说是全新的,我建议您从一些更基本的示例开始学习这个主题,例如 thisthis该问题具体与template template parameter(重复的template不是错误)有关,这是一个更高级的主题,您可以关注this作为一个很好的参考。 那么,这个问题更具体地与variadic template template parameter相关,例如thisthis

【讨论】:

  • 感谢详细的解释和代码。但是我正在看模板参数打包和解包以及is_specialization如何工作的解释。
  • @TechTotie 添加了
猜你喜欢
  • 2016-12-01
  • 2012-03-28
  • 1970-01-01
  • 1970-01-01
  • 2013-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-08
相关资源
最近更新 更多