有人可以解释下面带有模板参数包的代码。 它是如何工作的?在这种情况下,如何打包和解压缩模板参数:
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);
}
答案 0 :(得分:3)
以下是有关 variadic模板 语法, 打包 和 解压缩< / em> -有关所讨论的特定代码以及如何使其生效 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]是通用案例的基本模板(与继承无关),在进行任何特殊化之前,用于测试给定类型是否为特定模板。该模板参数为:(a)某些类型(b)某些其他类型必须是模板,并且带有一些未知的模板参数。
[B]是true
案例的专业化。调用方应提供两个模板参数,但只有第一个模板参数适合作为第二个模板参数给出的模板类型时,它才适合该专业化要求。请注意,该表达式需要两个模板参数:(a)我们将从其推断类型U<T, Args...>
和T
的模板参数Args
,以及(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<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>>
吗?是的,我们可以:
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
如果可变参数模板打包和打包对于您来说是全新的,我建议您从一些更基本的示例(例如this或this)开始学习本主题。
该问题与template template parameter
特别相关(重复的template
不是一个错误),这是一个更高级的主题,您可以按照this作为参考。
然后,问题更具体地与variadic template template parameter
有关,与this和this之类的示例有关。