Recently I was learning about C++ and variadic templates. I tried to write a template function that takes a container (I simplified it and I only work with list
in this question) and some other arguments and emplaces the other arguments to the container. My code looked like this:
#include <iostream>
#include <list>
#include <utility>
template <typename Container, typename... Args>
void my_emplace(Container &c, Args &&... args){
c.emplace_back(std::forward<Args>(args)...);
}
int main(void) {
std::list<int> l = {1, 2};
my_emplace(l, 3, 4, 5);
for (auto i : l)
std::cout << i << ", ";
return 0;
}
However, the code did not work:
$ g++ -std=c++17 test.cpp
...
/usr/include/c++/7/ext/new_allocator.h:136:4: error: new initializer expression list treated as compound expression [-fpermissive]
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I found a solution on the internet -- the line c.emplace_back(std::forward<Args>(args)...);
is replaced by (c.emplace_back(std::forward<Args>(args)), ...);
. The code works perfectly fine with it.
This is the part that I do not understand. I have never seen this kind of syntax.
Thank you for your answers.
Assume args is (1, 2, 3, 4), this call:
c.emplace_back(std::forward<Args>(args)...);
basically means:
c.emplace_back(1, 2, 3, 4);
so you can't construct int with these arguments to emplace_back
hence a compile error.
And this call:
(c.emplace_back(std::forward<Args>(args)), ...);
means
c.emplace_back(1), c.emplace_back(2), c.emplace_back(3), c.emplace_back(4);
Second call expands the whole expression with comma operator, its called Fold Expressions
its added in C++17 you can read more about it Fold Expression