[英]Why the second initialization work while the first one fail because of the "element type does not match"?
In c++ primer-initializing a Container as a copy of another container.在 C++ 入门中,将一个容器初始化为另一个容器的副本。
The element types in the new and original containers can differ as long as it is possible to convert the elements we are copying to the element type of the container we are initializing.只要可以将我们正在复制的元素转换为我们正在初始化的容器的元素类型,新容器和原始容器中的元素类型就可以不同。
For example:例如:
vector<const char*> articles = {"a", "an", "the"};
vector<string> words(articles) ; //error:element types must match
forward_list<string> words(articles.begin(), articles.end()); // ok, convert const char* to string
My question is why the second initialization work while the first one fail because of the element type does not match ?我的问题是为什么第二个初始化工作而第一个因为元素类型不匹配而失败?
The first line calls the constructor with an initializer_list of the same type as the element type ( const char*).第一行使用与元素类型 (const char*) 相同类型的 initializer_list 调用构造函数。 something like this:
像这样:
vector<T>(initializer_list<T> t ) {....}
--> OK! --> 好的!
The second is a copy-constructor call which is only defined for the same element type.第二个是复制构造函数调用,它只为相同的元素类型定义。
vector<T>(const& vector<T> t) {...}
What you did is something like this:你所做的是这样的:
vector<string>(const& vector<const char*> t){..}
--> Which does not exist! --> 哪个不存在!
First line performs copy-list-initialization (cfr. initializer_list
constructor ).第一行执行 复制列表初始化(参见
initializer_list
构造函数)。
Second line has no matching constructor since the types don't match (it can't call a copy constructor).第二行没有匹配的构造函数,因为类型不匹配(它不能调用复制构造函数)。
Third line instead uses the iterator range constructor which emplace-constructs elements and has a viable const char*
to string
conversion to use.第三行改为使用迭代器范围构造函数,该构造函数用于构造元素并具有可行的
const char*
到string
转换以供使用。
My question is why the second initialization works while the first one fails
我的问题是为什么第二次初始化工作而第一个失败
You're constructing a something .你正在构建一个东西。 This isn't done by magic, it just has to call one of the something 's constructors.
这不是靠魔法完成的,它只需要调用something的构造函数之一。 Any expression which can't match one of the constructors, can't compile.
任何无法匹配其中一个构造函数的表达式都无法编译。
So, let's first consider所以,让我们首先考虑
vector<const char*> articles = {"a", "an", "the"};
vector<string> words(articles);
Now, we need some std::vector
constructor that makes sense with this expression.现在,我们需要一些对这个表达式有意义的
std::vector
构造函数。 They're listed here , and the only ones that come close to matching are numbers 5 and 6 (at the time of writing - they're the copy and move constructors).它们在此处列出,唯一接近匹配的是数字 5 和 6(在撰写本文时 - 它们是复制和移动构造函数)。
The move constructor is out because we're not using std::move
or otherwise working directly on an rvalue reference, so let's take a look at the copy constructor:因为我们没有使用
std::move
或以其他方式直接处理右值引用,所以移动构造函数已失效,所以让我们看看复制构造函数:
vector<string>::vector<string>(const vector<string> &other);
Note that this isn't templated to take any argument type, or to take a vector of any type: it only matches a const reference to a vector of exactly the same type.请注意,这不是模板化以采用任何参数类型,或采用任何类型的向量:它只匹配对完全相同类型的向量的 const 引用。 Even though
const char *
is implicitly convertible to std::string
, the type vector<string>
is still not the same as vector<const char *>
.即使
const char *
可以隐式转换为std::string
,类型vector<string>
仍然与vector<const char *>
。 So, no constructor matches the argument type given.因此,没有构造函数与给定的参数类型匹配。
Then, consider然后,考虑
forward_list<string> words(articles.begin(), articles.end());
The std::forward_list
constructors are listed here . 此处列出了
std::forward_list
构造函数。 Note number 4:注意编号 4:
template< class InputIt >
forward_list(InputIt first, InputIt last,
const Allocator& alloc = Allocator() );
Firstly, this is templated on the iterator type, so passing vector<string>::iterator
or vector<const char *>::iterator
or whatever is no problem.首先,这是在迭代器类型上模板化的,因此传递
vector<string>::iterator
或vector<const char *>::iterator
或任何问题都没有问题。 Secondly, the conversion to std::string
from const char *
is sufficient for this overload to actually compile once it is selected.其次,从
const char *
到std::string
的转换足以让这个重载在被选中后实际编译。
Now, a couple of notes:现在,有几个注意事项:
You mentioned the explicit
keyword: this just prevents a single-argument constructor being used as an implicit conversion.您提到了
explicit
关键字:这只是防止将单参数构造函数用作隐式转换。 It doesn't affect higher types though: even if string::string(const char *)
is allowed as an implicit conversion, that doesn't make vector<const char *>
convertible to vector<string>
.不过,它不会影响更高的类型:即使允许
string::string(const char *)
作为隐式转换,也不会使vector<const char *>
转换为vector<string>
。 That still has to go through one of vector
's constructors.这仍然必须通过
vector
的构造函数之一。
We're mostly talking here about how an overload (in this case an overloaded constructor) is selected.我们在这里主要讨论如何选择重载(在本例中为重载构造函数)。 It's entirely possible the compiler can select an overload, and then still fail to compile.
完全有可能编译器可以选择重载,然后仍然无法编译。 For example, using that second iterator range constructor, where the iterators point to some incompatible (not even explicitly convertible) type.
例如,使用第二个迭代器范围构造函数,其中迭代器指向一些不兼容(甚至不能显式转换)的类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.