为什么我不能将std::unique_ptr用作“template<class> class”参数?

5
这段代码:

#include <memory>

template <template <typename> class Ptr>
class A { Ptr<int> ints; };

using B = A<std::unique_ptr>;

产生以下错误(使用GCC 6.3):
a.cpp:6:28: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class> class Ptr> class A’
 using B = A<std::unique_ptr>;
                            ^
a.cpp:6:28: note:   expected a template of type ‘template<class> class Ptr’, got ‘template<class _Tp, class _Dp> class std::unique_ptr’

现在,我可以这样解决这个问题:
template <typename T>
using plugged_unique_ptr = std::unique_ptr<T>;
using B = A<plugged_unique_ptr>;

但我为什么要这样做呢?我的意思是,为什么编译器不愿意使用std::unique_ptr的第二个模板参数默认值,并允许将std::unique_ptr用作A的模板实参?


1
请注意,它应该可以编译自 C++17 以来的版本。 - HolyBlackCat
@HolyBlackCat,你能告诉我为什么C++17可以使这个代码工作吗? - rubenvb
@rubenvb 这个页面有一些解释。 - HolyBlackCat
@HolyBlackCat 我猜你想表达的是该页面上的这一段:“为了将模板参数 A 与模板模板参数 P 匹配,A 的每个模板参数都必须与 P 的相应模板参数完全匹配(直到 C++17)。P 必须至少与 A 一样专业化(自C++17起)。” - rubenvb
可能是模板模板参数和默认值的重复问题。 - Arne Vogel
3个回答

6
由于模板模板参数需要完全匹配,因此默认的模板参数在这里不相关。请注意,将模板模板参数扩展为两个模板参数只会凭运气起作用:实现允许添加比标准定义的更多的模板参数,在 std 容器周围的 SFINAE 的情况下,一些实现通常会这样做。
这也是我通常建议不要使用任何模板模板参数的主要原因,而是只使用普通的模板类型名称。如果您需要访问嵌套的模板类型,请提供内部访问器,例如 value_type 或外部访问器,例如 tuple_element,在模板内部访问这些类型。
注意:显然,这在 C++17 中已经改变,匹配不再是精确的,但略微放松了,但更加复杂。尽管如此,我仍然建议总体上不要使用模板模板参数。

有时候你需要它们,如果你想应用多个内部模板参数。 - einpoklum
@einpoklum 我确定有时候你需要它们,但我不确定“应用多个内部模板参数”的意思是什么。你能举个例子吗? - rubenvb
1
template <template <typename> class Ptr> struct buffers_t { Ptr<foo[]> foos; Ptr<bar[]> bars; Ptr<baz[]> bazes; } - einpoklum
@einpoklum 有时候显而易见的事情也会被忽略。感谢您抽出时间 :). - rubenvb

4

std::unique_ptr有一个带默认值的第二个模板参数,因此template <typename> class Ptr无法匹配std::unique_ptr

template <typename...> class Ptr将起作用

cppreference


虽然没有完全回答我的问题,但这是一个聪明的解决方法,所以点赞! - einpoklum
1
我会倾向于使用 template<template<typename, typename...> class Ptr> 来明确期望参数的数量。 - Caleth

1
正如@HolyBlackCat所建议的那样,我们不再需要使用任何C++17的解决方法- OP的代码确实可以编译(coliru.com)。
GCC 6.3.0默认编译C++14代码,并且不应用此语言语义更改。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接