C++ Variadic Templates for a General-Purpose and Fast Data Storage Container Builder
template< typename ... Args>
auto build_array(Args&&... args) -> std::array<typename std::common_
type<Args...>::type, sizeof...(args)>
{
using commonType = typename std::common_type<Args...>::type;
return {std::forward<commonType>(args)...};
}
int main()
{
auto data = build_array(1, 0u, 'a', 3.2f, false);
for(auto i: data)
std::cout << i << " ";
std::cout << std::endl;
}
Hey guys, I cannot understand the above code. So basically, the code is to write a function that takes any number of elements of any type, which can, in turn, be converted into a common type. The function should also return a container having all the elements converted into that common type, and it should also be fast to traverse. This is a books solution.
From what I understand <typename... Args>
is to allow a variation of parameters. Then, (Args&&...args)
also allows for a variety of parameters, but only rvalues? I do not understand the arrow notation and the rest of the function declaration. Like what is the difference between each of them. Additionally, the book also passes in ? for the templates such as, std::array<?,?>
?
Finally, what does the return statement even mean (ending with an ellipsis?) ? and forward? Sorry, I am rambling on, but I just cannot make sense and obtain a detailed overview of what is going on. It would be really kind of you if you can elaborate on this?
but only rvalues?
When you see T&&
,
- if
T
is not a template parameter, thenT&&
means an rvalue reference toT
, which can bind to rvalules only; - if
T
is a template parameter, thenT&&
means a forwarding/universal reference toT
, which can bind to both rvalue and lvalues.
Therefore, in your case, since Args
is a template parameter (precisely a type template parameter pack, number (2) here), Args&&... args
expands to a comma separated sequence of function parameter declarations each of which as type a forwarding reference. For instance, if you pass 3 arguments to build_array
, the deduction takes place as if you had a declaration like this:
template<typename Arg1, typname Arg2, typname Arg3>
auto build_array(Arg1&& arg1, Arg2&& arg2, Arg3&& arg3)
-> std::array<typename std::common_type<Arg1, Arg2, Arg3>::type, 3>
what does the return statement even mean (ending with an ellipsis?) ?
Again, ...
is to expand some variadic thing in a comma separated sequence of things. So if args
in
return {std::forward<commonType>(args)...};
is actually 3 things, then that statement is expanded to
return {std::forward<commonType>(arg1), std::forward<commonType>(arg2), std::forward<commonType>(arg3)};
Notice the position of the ellipsis. f(args)...
is expanded to f(arg1), f(arg2), f(arg3), …
, whereas f(args...)
would be expanded to f(arg1, arg2, arg3, …)
.
and forward?
That's probably the less easy to understand bit, and would require a dedicated question. However many questions on that topic exist already, so you just have to search for them, rather than asking a new one. Here an answer of mine where I've most clearly explained the difference between std::move
and std::forward
. If you set understanding that answer of mine as your target, you'll understand std::forward
(and std::move
) and everything will be clearer.
I do not understand the arrow notation and the rest of the function declaration.
Essentially,
auto f(/* parameters */) -> SomeType
is equivalent to
SomeType f(/* parameters */)
with the advantage that in the former SomeType
can refer to types that are in /* parameters */
, if needed. In your case the return type makes use of Args
.
the book also passes in
?
for the templates such as,std::array<?,?>
?
Probably the book is just trying to guide you through argument deduction, and it's using ?
to mean "we don't know yet what it is; keep reading".