C++_可变参数模板到emplace_back再到construct再到forward
1、可变参数模板


具体定义如下图所示:

编写一个可变参数版本:


1.1sizeof…运算符

2、emplace_back与emplace
在我学习这个可变参数模板知识时想起了,请两天在浏览stl的容器是,有这么两个函数emplace_back与emplace,定义分别如下
template <class... Args>
iterator emplace (const_iterator position, Args&&... args);
template <class... Args>
void emplace_back (Args&&... args);
emplace_back在容器尾部插入元素,比如vector<int> ve;
我的第一反应是可以如下操作
ve.emplace_back(100,200,300) 但是是错误的,这是纳闷了,不是说好的多参数吗?我又查阅了大量资料,发现不是可变模板参数问题,是函数本身的实现方式是不一样的;此函数是会调用构造函数实现的 ,我又查阅了函数源码。vector.tcc文件如下:
vector<_Tp, _Alloc>::
emplace_back(_Args&&... __args)
{
if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
{
_GLIBCXX_ASAN_ANNOTATE_GROW(1);
_Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
std::forward<_Args>(__args)...);
++this->_M_impl._M_finish;
_GLIBCXX_ASAN_ANNOTATE_GREW(1);
}
else
_M_realloc_insert(end(), std::forward<_Args>(__args)...);
#if __cplusplus > 201402L
return back();
#endif
}

以上调用方法会产生以下实例,可见可变参数模板是没问题的

上面提到的问题出在了对参数处理的情况上,当我们把鼠标放到construct上会有以下提示:

第一个参数分配器,第二个参数指针-指向一个适合构造tp对象内存大小和对齐的指针,第三个参数构造函数参数
重点来了empalce_back()与emplace()调用的是构造函数,其功能还是插入一个元素对象,虽然可变参数模板可以传多个参数,但没有相应的构造函数匹配,所以错误。接下来讲构造函数可以传多个参数的传递过程。
3、allocator.construct()的功能
 C++11源码如下:
template <class U, class... Args>
void construct (U* p, Args&&... args);
emplace_back()的args参数进来后被传递到T的构造函数充当参数,一个参数很好理解,那么一堆呢(一个包呢),此时另一个类型出现了,std::forward<T>.传递参数需要有相应的构造函数匹配
4、std::forward
lvalue (1) | template <class T> T&& forward (typename remove_reference<T>::type& arg) noexcept; |
---|
rvalue (2) | template <class T> T&& forward (typename remove_reference<T>::type&& arg) noexcept; |
如果不是左值引用,则返回对的右值引用。
如果是左值引用,则函数返回而不修改其类型。
到这里可以看最终解释:



参考:C++ primer (第五版)
cplusplus.com - The C++ Resources Network
|