C++ 为类模板提供初始化列表构造函数

Posted

技术标签:

【中文标题】C++ 为类模板提供初始化列表构造函数【英文标题】:C++ Supply initializer-list constructor for class template 【发布时间】:2013-02-11 02:14:19 【问题描述】:

我有一个带有模板参数 T 的类模板 Templ,而 Templ 类有一个类型为 T 的数据成员,称为 obj。我写了一个可变参数构造函数模板,它将参数转发给 obj 的构造函数:

template <class T>
class Templ

public:
     template <class... Args> explicit Templ (Args&&... args)
     : obj (std::forward<Args>(args)...)
     
     
private:
     T obj;
;

现在我意识到类型 T 可能是一个带有 init-list 构造函数的类,我希望它可以通过 Templ 访问。所以我检查了std::list::emplacestd::make_shared 做了什么。他们有一个像我一样的可变参数函数,但他们没有覆盖初始化列表。不知为何。

所以第一个问题:为什么?我的意思是,如果我使用带有 init-list ctor 的某个类 T,然后我使用 std::list&lt;T&gt; 怎么办?为什么 list::emplace 没有采用 initializer_list 的版本?也许我也应该这样做是有充分理由的……所以我想知道。

另外,不管 STL 做什么——我应该提供一个 init-list ctor 作为好的设计吗?我的意思是,它就像可变参数 ctor,对吧?允许用户选择任何类型或类 T 与 Templ 一起使用并直接调用为 T 定义的任何 ctor。即使它是一个采用 init-list 的 ctor。

【问题讨论】:

你的第一个问题是一个很好的问题,但是其他三个问题应该是单独的帖子。 @VaughnCato 我把其中一个分开了。我可以在 20 分钟内发布一次,所以我无法修复其余的……直到下一次 完成,现在只有 1 个问题 【参考方案1】:

转发initializer_list 构造函数的问题在于,除了最微不足道的参数类型之外的所有参数类型都不可推导出(Templates don't always guess initializer list types):

#include <map>
template<typename T> struct U 
   T t;
   template<typename...A> explicit U(A&&...a): t(std::forward<A>(a)...) 
   template<typename L, typename = typename std::enable_if<
      std::is_constructible<T, std::initializer_list<L>>::value>::type>
      explicit U(std::initializer_list<L> l): t(l) 
;
U<std::map<int, int>> m0, 1, 2, 3;  // fails, couldn't deduce 'L'

由于在大多数情况下您必须编写 mstd::initializer_list&lt;...&gt;...,因此只为原语提供它并没有多大意义,当然也不适合标准这样做。

如果您认为任何有趣的initializer_list 参数都可能用于容器类型,您可以查看Optionally supporting initializer_list construction for templates maybe wrapping containers 中采用的方法。

【讨论】:

我不希望包装容器,但我确实想支持一个具有 init-list ctor 的类。哪些情况下扣款无效?如果用作模板参数的类有一个 ctor,它采用原始类型变量的初始化列表,或者我定义的类的对象的初始化列表(不是一对或容器或类似的东西),它会工作吗?另外,我必须使用 enable_if 吗?如果我不这样做会怎样? @fr33domlover 如果您的初始化程序是x1, x2, ... 的形式,其中所有x 都是相同类型的prvalue 表达式,那么您很好;问题是如果你有嵌套的大括号。如果要使用统一初始化,enable_if 是必需的; initializer_list 构造函数是贪婪的 (13.3.1.7)。 我们当然需要一个用于下一个 c++ 的 initializer_tuple 内在类型,它允许完美地转发大括号初始化列表,无论它们是同质的还是异质的。

以上是关于C++ 为类模板提供初始化列表构造函数的主要内容,如果未能解决你的问题,请参考以下文章

无法在 C++ 中模板的初始化列表中使用 lambda

C++初始化列表构造函数VS普通构造函数

C++ 构造函数初始化列表

为啥 C++ 列表初始化也会考虑常规构造函数?

构造函数中的 C++ 初始化列表

C++:初始化成员变量(无参构造|有参构造|初始化列表)