This is the seventh day of my participation in the August More text Challenge. For details, see:August is more challenging

1. Variable parameter template

Let’s start with a brief introduction to variable-parameter templates:

A variable-argument template is a template function or class that takes a variable number of arguments. A variable number of parameters are called parameter packages: 1. Template parameter packages. 2. Function parameter package, indicating zero or more parameters.

Function variable template parameter definition mode:

void name(a){}
template <typename T,typename. Args>void name(T &t,Args& ... args){
    /* insert args... * /
}
Copy the code

Details:

1. Versions of non-mutable template parameters must exist, otherwise wireless recursion may occur;

If name(args…) is called recursively ; Will take the args… Divided into one and a package;

Variable parameter template class definition:

template< class... Types >
class AA;
Copy the code

The expansion mode of parameter package of variable parameter template class is different from that of variable parameter template function. The expansion mode of parameter package of variable parameter template class is more complex than that of variable parameter template function through template specialization and inheritance

sizeof… The operator

When we need to know how many elements are in a package, we can use sizeof… Operator.

template <typename. Args>void AA(Args ... args){
    cout<<sizeof. (Args)<<endl;// Number of type parameters
    cout<<sizeof. (args)<<endl;// Number of function arguments
}
Copy the code

sizeof... (Args) indicates the number of categories in the parameter, sizeof... (args) indicates how many parameters there are

2. Emplace_back and emplace

When I was learning about the mutable parameter template, please browse the STL container for two days. There are two functions, emplace_back and emplace, defined as follows

template <class... Args>
iterator emplace (const_iterator position, Args&&... args);
Copy the code
template <class... Args>
  void emplace_back (Args&&... args);
Copy the code

Emplace_back insert element at the end of the container, vector<int> ve;

My first reaction was to do the following

Ve. Emplace_back (100,200,300) but it is wrong. I looked up a lot of data, and found that the variable template parameters are not the problem, but the implementation of the function itself is different; This function is implemented by calling the constructor, and I consulted the source code of the function. The vector. TCC file looks like this:

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(a);#endif
      }
Copy the code

The above method call will produce the following instance, and the variable parameter template is fine

The problem mentioned above is the handling of parameters. When we put the mouse over Construct, we will get the following prompt:

The first argument allocator, the second argument pointer - to a pointer suitable for constructing the memory size and alignment of the TP object, and the third argument constructor argument

The important point is that empalce_back() and emplace() call the constructor, whose function is to insert an element object. Although the mutable parameter template can pass multiple arguments, there is no corresponding constructor match, so the error. The next step is how a constructor can pass multiple arguments.

3, STD: : forward

The statement
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;

Function:

If it is not an lvalue reference, an Rvalue reference to the pair is returned.

If it is an lvalue reference, the function returns without changing its type.

How to pass constructor arguments

Such as STR. Emplace_back (10, ‘A’); The pattern in the construct call extends to STD ::forward<int>(10), STD ::forward<char>(A). By calling forward, we ensure that if emplac_back is called with an Rvalue, construct also gets an Rvalue. The correctness of the calling process is guaranteed.

Above is this article, welcome everyone to criticize and correct.