使用 std::initializer_list 构造函数而不产生歧义?
Using std::initializer_list constructor without creating ambiguities?
>我有一个名为Shape
的类,可以从任何可迭代对象初始化,还有一个名为Array
的类,它只包含一个Shape
。但是,当我尝试初始化Array
时,我遇到了一个无法解释的编译错误:
class Shape
{
public:
template<typename Iterator>
Shape(Iterator first, Iterator last)
: m_shape(first, last) {}
template <typename Iterable>
Shape(const Iterable& shape)
: Shape(shape.begin(), shape.end()) {}
template<typename T>
Shape(std::initializer_list<T> shape)
: Shape(shape.begin(), shape.end()) {}
private:
std::vector<std::size_t> m_shape;
};
class Array
{
public:
Array(const Shape& shape)
: m_shape(shape) {}
private:
Shape m_shape;
};
int main() {
Shape s{0}; // ok
Array a1({1, 2}); // ok
Array a2({0}); // error
}
编译错误出现在Shape
的第二个构造函数上:
prog.cxx:35:16: required from here
prog.cxx:14:23: error: request for member ‘begin’ in ‘shape’, which is of non-class type ‘const int’
: Shape(shape.begin(), shape.end()) {}
~~~~~~^~~~~
prog.cxx:14:38: error: request for member ‘end’ in ‘shape’, which is of non-class type ‘const int’
: Shape(shape.begin(), shape.end()) {}
~~~~~~^~~
我不明白这里发生了什么。为什么调用Iterable
构造函数而不是initializer_list<T>
构造函数?带{0}
的Shape
构造函数和Array
构造函数有什么区别?
代码格式不正确,但不是因为 gcc 声称的原因。当你写:
Array a2({0});
我们使用初始值设定项{0}
对Array
的所有构造函数进行重载解析。
选项 #1 是:
Array(Shape const& );
在此基础上,我们将递归尝试使用{0}
复制初始化Shape
,由于在列表初始化期间优先处理std::initializer_list
,最终会调用std::initializer_list<int>
构造函数模板。
但是,这只是一种选择。选项 #2 是:
Array(Array&& );
隐式移动构造函数。为了检查这是否是候选者,我们看看是否可以使用{0}
初始化Array
,这基本上是重新开始。在下一层中,我们看看是否可以使用0
初始化Shape
(因为我们删除了一层),我们可以 -这就是你接受所有事物的构造函数模板。这确实涉及两个用户定义的转换序列,但这对于列表初始化是可以的。
所以我们有两个选择:
- 选项#1:
{0} --> Shape
- 选项#2:
0 --> Shape --> Array
两者都不比另一个好,所以电话是模棱两可的。
简单的解决方法是向构造函数模板添加一个约束,使其实际上是一个范围。无论如何,这通常是很好的做法,因为您不希望is_constructible_v<Shape, int>
是真的......
相关文章:
- "error: no matching function for call to"构造函数错误
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 选择要调用的构造函数
- 数组初始值设定项的构造函数歧义
- C++ 类的构造函数和函数调用运算符 () 重载之间的歧义
- C++ 显式多参数构造函数歧义
- c++ 构造函数重载歧义与initializer_list
- 解决C++构造函数和调用歧义
- 使用 std::initializer_list 构造函数而不产生歧义?
- 如何解决转换构造函数和普通构造函数之间的歧义
- 如何处理默认构造函数和重载构造函数之间的歧义
- C++11:在按值传递参数初始化时转换构造函数和转换函数之间的歧义
- 当目标类有多个构造函数时,消除强制转换操作符的歧义
- 构造函数在尝试支持文字时重载歧义
- 重载构造函数之间的歧义
- 为什么这两个构造函数一起不会产生歧义错误?
- 基构造函数和派生构造函数之间的歧义