可变参数模板模板和完美转发

Posted

技术标签:

【中文标题】可变参数模板模板和完美转发【英文标题】:Variadic template templates and perfect forwarding 【发布时间】:2011-09-23 02:33:31 【问题描述】:

object generator pattern 上的This question 让我开始思考如何实现自动化。

本质上,我想自动创建 std::make_pairstd::bind1ststd::mem_fun 等函数,这样您就不必为每个模板类类型编写不同的函数,而可以编写一个可变参数模板模板函数一次处理所有案件。这个函数的用法如下:

make<std::pair>(1, 2);         // equivalent to std::make_pair(1, 2)
make<std::binder2nd>(&foo, 3); // equivalent to std::bind2nd(&foo, 3);

可以写这个函数make吗?我已经尝试过了,但它在 GCC 4.5 或 4.6 中不起作用:

template <template <typename...> class TemplateClass, typename... Args>
TemplateClass<Args...> make(Args&&... args)

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

如果我尝试致电(例如)make&lt;std::pair&gt;(1, 2) 我就会得到

error: no matching function for call to 'make(int, int)'

我在这里的任何地方都有语法错误吗? 或者这是对的而 GCC 是错的? 或者这在 C++0x 中根本不可能?

[编辑]

提案N2555 似乎表明这是允许的,GCC claims to have implemented it in GCC4.4。

【问题讨论】:

我认为有一个问题,可变参数模板模板参数只会匹配可变参数模板类,IIRC。此外,感谢std::bindmem_fnbindNth 将被 C++0x 淘汰和弃用。 @Xeo:您​​的意思是 GCC 或标准中的问题? N2555 表明它应该是可能的,并且 GCC 声称已在 4.4 中实现它(请参阅我的编辑) @Peter:提案并没有说它已被 FDIS 采纳(但我当然希望它被采纳)。让我检查一下。 编辑:FDIS有提案中的措辞,所以我不知道问题出在哪里。 我想知道模板参数的推导方式是否存在问题?例如,是否 Args 最终成为引用类型,这会导致某些 SFINAE 效果在解析期间丢弃您的 make 函数? @PeterAlexander:正如上面提到的答案,这似乎是当前 gcc 的一个错误。供您参考,通过使用辅助(无意义?)类模板,ideone(gcc-4.5.1) 以某种方式编译了它。 【参考方案1】:

完全正确。我希望它能够工作。所以我认为 GCC 拒绝这一点是错误的。 FWIW:

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



// [js@HOST2 cpp]$ clang++ -std=c++0x main1.cpp
// [js@HOST2 cpp]$

【讨论】:

看来是时候让我看看 clang 了 :-)【参考方案2】:

这可能是 GCC 的怪癖。我可以获得以下内容以使用开发快照(我现在没有 4.6 的副本):

template<
    template<typename...> class TemplateClass
    , typename... Args

    , typename Result = TemplateClass<Args...>
    // Also works with the arguably more correct
    // , typename Result = TemplateClass<
    //     typename std::decay<Args>::type...
    // >
>
Result
make(Args&&... args)
 /* as before */ 

【讨论】:

【参考方案3】:

这是完全错误的——以make_shared 为例。 make_shared 的重点是使用它可以节省运行时效率。但是如果我尝试使用make&lt;std::shared_ptr&gt; 会发生什么?不要认为那会很成功。或者只有一些构造函数参数是模板参数而其他不是模板参数的类型呢?例如,make&lt;std::vector, int&gt;(other_vector.begin(), other_vector.end()); - 迭代器的类型不参与,但无论如何你都会传递它们。

写一个通用的make函数是不可能的。

至于标准,从那时起它很容易被删除。您必须检查 FDIS。

【讨论】:

重点不是创建一个构造 any 类的函数,就像我描述的那样:即模板参数完全来自构造函数参数的函数。 理论上,可以专门针对shared_ptr 使用该方法,但总的来说,我同意这会导致比它解决的问题更多的问题。

以上是关于可变参数模板模板和完美转发的主要内容,如果未能解决你的问题,请参考以下文章

可变参数模板

如何对可变参数函数中的所有参数调用 std::forward ?

[C++11 模板的改进] --- 可变参数模板

为啥可变参数模板的模板特化与非可变模板的特化不同?

C++11 ——— 可变参数模板

C++11 ——— 可变参数模板