如何展开模板专业化

How to unroll template specializations

本文关键字:专业化 何展开      更新时间:2023-10-16

我正在尝试使用模板元编程来获取参数包中指定索引处的类型。我有下面的代码,但由于某种原因,它总是返回int,有人能告诉我我做错了什么吗?

#include <string>
#include <iostream>
using std::cout;
using std::endl;
using std::string;
template <int current_index, typename... Vs>
struct TypeForIndex {};
template <int current_index, typename Head, typename... Tail>
struct TypeForIndex<current_index, Head, Tail...> : private TypeForIndex<current_index + 1> {
    using type = Head;
};
template <int current_index, typename Tail>
struct TypeForIndex<current_index, Tail> {
    using type = Tail;
};
int main() {
    TypeForIndex <2, int, double, string>::type a {"hello"};
    cout << a << endl;
    return 0;
}

上面的代码应该返回string作为a的类型,但不知何故,它始终是int

TypeForIndex<2, int, double, string>

好的,图案匹配时间。首先,它明显匹配

template <int current_index, typename... Vs>
struct TypeForIndex {};

因此没有错误。它与其他专业相匹配吗?

A:

template <int current_index, typename Head, typename... Tail>
struct TypeForIndex<current_index, Head, Tail...>

B:

template <int current_index, typename Tail>
struct TypeForIndex<current_index, Tail>

好吧,它匹配(A)而不匹配(B)。

对于(A),current_index2HeadintTail...double, std::string

template <int current_index, typename Head, typename... Tail>
struct TypeForIndex<current_index, Head, Tail...> : private TypeForIndex<current_index + 1> {
    using type = Head;
};

现在,private TypeForIndex<current_index + 1>几乎没用了。它总是只匹配主专门化,它有一个空的主体,而且它是私有的,所以没有人会注意到它。我们可以在不改变程序行为的情况下删除它。

template <int current_index, typename Head, typename... Tail>
struct TypeForIndex<current_index, Head, Tail...> {
    using type = Head;
};

如上所述,Headint。所以我们得到type=int

就是这样,这就是为什么type就是int

你做错了什么几乎就是一切?除了编译(即,存在与签名匹配的主要专业化),您提供的代码与您在文本中描述的内容无关。即使current_index+1是一个字符串,我也不希望它存在于代码中,它会按照您的文本进行描述。

抛弃了除初级专业化之外的所有东西,这是有效的:

template <typename Head, typename... Tail>
struct TypeForIndex<0, Head, Tail...> {
  using type = Head;
};
template <int current_index, typename Head, typename... Tail>
struct TypeForIndex<current_index, Head, Tail...>:
  TypeForIndex<current_index-1, Tail...>
{};

如果传递过大的索引,则它适当地缺少CCD_ 18的定义。

我也会使用size_t而不是int

以下是您的解决方案。

#include <string>
#include <iostream>
using std::cout;
using std::endl;
using std::string;
template <int current_index, typename... Vs>
struct TypeForIndex {};
template <int current_index, typename Head, typename... Tail>
struct TypeForIndex<current_index, Head, Tail...> : TypeForIndex<current_index - 1, Tail...> {};
template <typename Head, typename... Tail>
struct TypeForIndex<0, Head, Tail...> {
    using type = Head;
};
int main() {
    TypeForIndex <2, int, double, string, char>::type a ("hello");
    cout << a << endl;
}