C++11使variadic构造函数了解一个初始化列表的初始化列表
C++11 making variadic constructor understand an initialization list of initialization lists
假设我有一个Point和的类和一个Points数组,其中点数由模板参数给定。如何使用大括号进行初始化?如果我使用:
class Point {
public:
float x, y;
Point(float x, float y) : x(x), y(y) {}
};
template <size_t N>
class Array {
private:
std::array<Point, N> _points;
public:
template <typename... Points>
Array(const Points& ... points) : _points({ points... }) {
}
};
然后这个工作:
Array<2> a{Point{1,1}, Point{2, 2}};
但是,如果我不提供明确的Point
对象,我会在Xcode中得到一个错误:
Array<2> c{{1,1}, {2, 2}};
错误为:"没有用于初始化数组<2>的匹配构造函数"。对于特定的构造函数,它说"候选构造函数不可行:需要0个参数,但提供了2个"。
我该如何让它发挥作用?
为什么您的代码不起作用
您正在支撑的init列表中支撑,{{1, 1}, {2, 2}}
。那东西没有类型。这只是一堆东西。模板推导实际上不起作用,因为它可能是任何东西——可以从该列表中构建无限数量的类型。尽管您显然希望Points...
成为Point
,但这是行不通的。
该怎么办
将支持的初始化列表表示任意数量的T
s(对于某些类型的T
)的唯一方法是使用std::initializer_list
:
Array(std::initializer_list<Point> points) { ... }
但是,要从initializer_list
初始化数组,您需要类似std::copy
的东西,但由于Point
不是默认可构造的,因此这是一个不启动的程序。
我们可以直接取一个数组:
Array(std::array<Point, N> const& a)
: _points(a)
{ }
这可以让你做你想做的事。或者至少,加上一些额外的大括号:
Array<2> c{{{{1, 1}, {2,2}}}};
牙套太多了,真烦人!
因此,我喜欢的一个技巧是实际创建一个使用N
Point
s的构造函数,这正是您想要开始的。我们可以通过使用索引序列技巧使Array
成为部分专业化来做到这一点:
template <size_t N, class = std::make_index_sequence<N>>
class Array;
template <size_t N, size_t... Is>
class Array<N, std::index_sequence<Is...>> {
private:
std::array<Point, N> _points;
template <size_t>
using Point_ = Point;
public:
Array(Point_<Is>... points)
: _points{{points...}}
{ }
};
这里,Point_<I>
只是Point
的一个别名模板,我们使用它只是将索引序列解压缩为一堆Point
s。因此,该构造函数是一个非模板,它精确地占用N
Point
s,然后我们可以将其与适量的大括号一起使用:
Array<2> c{{1, 1}, {2,2}}; // ok!
†嗯,不是一个真正的不开始。你可以做几件事来让它发挥作用。您可以使Point
默认为可构造的,此时您可以编写:
Array(std::initializer_list<Point> il)
{
std::copy(il.begin(), il.begin() + std::min(il.size(), N), _points.begin());
}
或者,即使不使Point
默认可构造,也可以使用索引序列技巧在委托构造函数的帮助下进行初始化:
public:
Array(std::initializer_list<Point> il)
: Array(il, std::make_index_sequence<N>{})
{ }
private:
template <size_t... Is>
Array(std::initializer_list<Point> il, std::index_sequence<Is...> )
: _points{{(Is < il.size() ? il.begin()[Is] : Point(0,0))...}}
{ }
- C++类 - 初始化列表 - 递归 - 按值传递
- 在初始化列表之外手动调用基类的构造函数
- C++:带有大括号初始化列表的函数调用表达式 - 标准是否规定在单个元素列表的微不足道的情况下忽略大括号?
- std::map与谓词与初始化列表
- 类内初始化与构造函数初始化列表的顺序
- 当返回语句时,逗号运算符、大括号初始化列表和 std::unique_ptr 组合在一起
- 使用初始化列表填充C++中的多维结构数组时出现问题
- 如何在初始化列表中的构造函数之后初始化变量/对象?
- C++初始化列表与分配值
- C++初始化列表中的向量集大小或调整大小
- 在构造函数初始化列表中使用 std::variant
- emplace_back初始化列表错误,当初始化列表在独立变量上工作时
- 解释了构造函数成员初始化列表
- 使用初始化列表时如何获取私有数据?
- 用初始化列表和超类构造函数声明子类构造函数的正确方式
- 如何在成员初始化列表中声明共享指针
- 庞大的初始化列表,如何修复"fatal error C1060: compiler is out of heap space"
- 我可以检查初始化列表中设置的构造函数主体中的变量吗
- 使用整数初始化列表初始化长双精度的向量
- 是否可以在C++中使用初始化列表设置数组的特定成员?