我看到了来自this answer的代码片段,我似乎无法理解模板和类型名称的排列如何创建main()中显示的最终函数调用。
特别是,可变参数模板模板的安排和std :: forward的使用让我很困惑。
任何人都可以打破这段代码,以便我能更好地理解它吗?
#include <utility>
template <template <typename...> class TemplateClass, typename... Args>
TemplateClass<Args...> make(Args&&... args)
{
return TemplateClass<Args...>(std::forward<Args>(args)...);
}
int main()
{
make<std::pair>(1, 2);
}
非常感谢任何帮助。
答案 0 :(得分:7)
这是一个带有模板 template-parameter 的函数模板:
template <template <typename, typename> class TT>
TT<int, double>
make(int i, double d)
{
return TT<int, double>(i, d);
}
您指定具有两个类型参数的类或别名模板,此函数将使用此模板的特化,使用int
和double
作为模板参数创建。例如:
make< std::pair >(42, 4.2);
这会返回std::pair<int, double>
。
我们现在可以“模板化”这个函数的(函数)参数:
template <template <typename, typename> class TT, typename Arg0, typename Arg1>
TT<Arg0, Arg1>
make(Arg0 a0, Arg1 a1)
{
return TT<A0, A1>(a0, a1);
}
模板参数Arg0
和Arg1
旨在从用于调用函数的(函数)参数的类型中推导出来:
int i = 42;
double d = 4.2;
make< std::pair >(i, d); // returns a `std::pair<int, double>`
对于更复杂的数据类型,我们可能希望使用完美转发:
make< std::pair >( 42, std::vector<int>(1000) );
这会返回std::pair<int, std::vector<int>>
。
make
的上述定义将移动通过std::vector<int>(1000)
创建的临时向量到第二个函数参数中。但是,它将复制从那里复制到通过TT<A0, A1>(a0, a1)
创建的对象。
我们可以更改make
的定义以实现完美转发,如下所示:
template <template <typename, typename> class TT, typename Arg0, typename Arg1>
TT<Arg0, Arg1>
make(Arg0&& a0, Arg1&& a1)
{
return TT<A0, A1>(std::forward<A0>(a0), std::forward<A1>(a1));
}
通过std::vector<int>(1000)
创建的临时向量将被移动到return语句中创建的对象中。
现在,我们可以将此函数模板推广到N个参数;模板 template-parameter 也必须进行通用化,以便您可以传递任何带有一些类型参数的类或别名模板。
template <template <typename...> class TemplateClass, typename... Args>
TemplateClass<Args...> make(Args&&... args)
{
return TemplateClass<Args...>(std::forward<Args>(args)...);
}
答案 1 :(得分:2)
template <template <typename...> class TemplateClass, typename... Args>
TemplateClass
本身就是一个需要变量模板参数的模板。如果没有可变参数部分,对于单个参数,它可能看起来像template <typename> class TemplateClass
,对于两个参数,它可能看起来像template <typename, typename> class TemplateClass
。 Args
是此函数模板make
的可变参数模板参数。
TemplateClass<Args...> make(Args&&... args)
返回的类型为TemplateClass<Args...>
,从原始模板参数到模板函数,并使用原始模板的可变参数Args
进行定义。 make
采用名为args
的可变参数包,通常称为“通用引用”(&&
,在这种情况下,这可能是也可能不是rvalue引用)。 / p>
{
return TemplateClass<Args...>(std::forward<Args>(args)...);
}
使用构造函数创建返回类型的对象,该构造函数接受最初提供给函数的所有参数。
完善转发用于确保为最初收到的每个参数维护值类别。 ...
扩展了它左边的内容,因此对于参数包中的每个参数,都应用std::forward
(这是必需的,因为std::forward
只接受一个参数。
简而言之,参考折叠和static_cast
的组合。基本上,如果参数是左值引用,则std::forward
的返回类型也是左值引用。如果它是右值引用,则返回类型是右值引用(类似于std::move
的结果)。
它们支持std::forward
和类似函数的机制,例如make
。另一个例子是标准库中的std::make_shared
函数。它们之所以如此命名,是因为它们可以绑定到“任何”引用(&
和&&
),因为C ++ 11中引入了引用折叠规则。