0

I've seen a code snippet here on the board that I don't understand:

struct expression_sequence
{
    template<typename... Ts>
    expression_sequence(Ts&&... ts) { }
};

template<typename T, class Tuple = std::vector<T>>
class vector
{
public:    
    template<typename... Elements>
    vector(Elements&&... elements)
    {
        m_elements.reserve(sizeof...(Elements));
        expression_sequence{ (m_elements.push_back(std::forward<Elements>(elements)), 0)... };
    }

private:
    Tuple m_elements;
};

What exactly is going on at expression_sequence{ (m_elements.push_back(std::forward<Elements>(elements)), 0)... }; and why is it working?

I don't understand why we need to surround m_elements.push_back(std::forward<Elements>(elements)) by ( and , 0). (Why 0, i.e. why an int?). And what's the type of (m_elements.push_back(std::forward<Elements>(elements)), 0)?

Community
  • 1
  • 1
0xbadf00d
  • 17,405
  • 15
  • 67
  • 107

1 Answers1

2

That's a workaround, waiting for the fold expression.

Currently, push_back accepts only one element, so you have no way to unpack the parameter list.
Using that trick, with a class and its (let me say) variadic constructor, you succeed in unpacking the parameter pack, but still that class expects a list of types, even if it doesn't use those parameters.
Because of that, using the surrounding parts ( and , 0) you are actually allowing the support struct to auto-deduce its types from a list of ints, so that that code compiles.

One could argue that the support struct is completely useless.
Of course, that's nothing more than a trick, because the fold expression are planned for the revision C++17.

skypjack
  • 49,335
  • 19
  • 95
  • 187
  • I still don't understand why `(m_elements.push_back(std::forward(elements)), 0)` is syntactically correct. `push_back` has return type `void`. So, what's the type of this expression? I've noticed that I can write `auto x = (1, 1, 1);` and the type of `x` is `int`. What is going on there? – 0xbadf00d Mar 04 '16 at 22:54
  • Never heard about [comma operator](http://en.cppreference.com/w/cpp/language/operator_other#Built-in_comma_operator) before? – skypjack Mar 04 '16 at 22:58
  • Ah, I see. Thus, the type of a expression `(foo(), 0)` is `int` for any `void foo() { }`, right? In the case here, the first expression is a parameter pack. However, the type of the expression here is `int`, too. (That's actually wrong I guess, cause the first expression is a parameter pack here). I've got some problems to understand why `(m_elements.push_back(std::forward(elements)), 0)` is a parameter pack which we can expand. – 0xbadf00d Mar 04 '16 at 23:10
  • @0xbadf00d That expression isn't a parameter pack. `elements` and `Elements` are. Expressions containing packs can be expanded. – Barry Mar 05 '16 at 00:19