-1

我已经从这个答案中看到了这段代码的片段,我似乎无法理解模板和类型名的排列如何创建 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);
}

任何帮助将不胜感激。

4

2 回答 2

7

这是一个带有模板模板参数的函数模板:

template <template <typename, typename> class TT>
TT<int, double>
make(int i, double d)
{
    return TT<int, double>(i, d);
}

您指定一个具有两个类型参数的类或别名模板,并且此函数将使用此模板的特化,使用intdouble作为模板参数创建。例如:

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

模板参数Arg0Arg1旨在从用于调用函数的(函数)参数的类型中推导出来:

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)将被移动到在返回语句中创建的对象中。


现在,我们可以将这个函数模板泛化为 N 个参数;模板模板参数也必须通用化,以便您可以传递任何带有一定数量类型参数的类或别名模板。

template <template <typename...> class TemplateClass, typename... Args>
TemplateClass<Args...> make(Args&&... args)
{
    return TemplateClass<Args...>(std::forward<Args>(args)...);
}
于 2014-09-22T08:08:54.053 回答
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参数包(在这种情况下, this 最终可能是也可能不是右值引用)。args&&

{
    return TemplateClass<Args...>(std::forward<Args>(args)...);
}

返回类型的对象是使用构造函数创建的,该构造函数接受最初提供给函数的所有参数。

完善转发用于确保为最初接收的每个参数维护值类别。扩展它左侧的...内容,因此对于参数包中的每个参数,std::forward应用 a (这是必需的,因为std::forward只接受一个参数。

完美转发是如何工作的?

简而言之,参考折叠和static_cast. 基本上,如果参数是左值引用,则返回类型std::forward也是左值引用。如果它是一个右值引用,则返回类型是一个右值引用(类似于 a 的结果std::move)。

“通用参考”(或“转发参考”)如何工作?

它们为类似功能的机制提供动力std::forward,就像make在这种情况下一样。另一个例子是std::make_shared标准库中的函数。它们之所以如此命名,是因为它们可以绑定到“任何”引用(&&&),因为 C++11 中引入了引用折叠规则。

于 2014-09-22T08:09:11.143 回答