ulak blade
ulak blade

Reputation: 2655

How to construct any object from variadic constructor parameters?

I am experimenting with making my own containers, and I am writing an Emplace method for my Vector class.

First, here are my Forward functions:

template<typename T>
T&& Forward(typename remove_reference<T>::Type& arg)
{
    return static_cast<T&&>(arg);
}

template<typename T>
T&& Forward(typename remove_reference<T>::Type&& arg)
{
    static_assert(!Internal::is_lvalue_reference<T>::Result);

    return static_cast<T&&>(arg);
}

They are basically identical to the std ones.

Now here is my Emplace method:

template<typename T>
template<class... ARGS>
void MyVector<T>::Emplace(ARGS&&... args)
{
    Add(Forward<ARGS>(args)...);
}

This gives me an error "function does not take 2 arguments", because Add isn't designed to work with variadic arguments. So instead I just do it in place:

template<typename T>
template<class... ARGS>
void MyVector<T>::Emplace(ARGS&&... args)
{
    if(size >= capacity)
    {
        AdaptCapacity();
    }

    data[size++] = value;
}

What am I supposed to put at _data[_size++] = value;? How can I construct any 'T' with the variadic arguments? If I pass a call of Forward to the constructor of T, it would just give me the same error as passing it to Add, because of the '...' syntax. What else can I do?

I tried looking inside std::vector and all I found was some function _Alty_traits::construct that doesn't seem to have any definition(a compiler intrinsic?)

Does that mean it's impossible for me to write a custom Emplace method?

Upvotes: 0

Views: 310

Answers (1)

Nir Friedman
Nir Friedman

Reputation: 17704

Normally, if date itself was a vector<T> or some such, you could do:

date[size++] = T(std::forward<ARGS>(args)...);

However, if you are writing your own vector, then data basically holds some raw memory. What you need is to construct an object directly into that raw memory. To do that, you need placement new:

new (date + size++) T(std::forward<ARGS>(args)...);

Note that this placement new issue is orthogonal to using variadics and such; you need placement new when writing push_back as well.

Edit: because you did not tells us the type or content of date, and based on your comments here, I'm assuming you did something like this:

data = new T[capacity];

If this is what you did, then you must use the first form I gave; using the second form would be undefined because you are constructing an object over another object (and then you can never call its destructor).

However, this is not the correct way to write a vector (or any other generic container). When a vector grabs more memory, it should only grab more memory and not construct anything (new T[capacity] default constructs all the entries in the dynamic array), in that case you must use the second form.

Upvotes: 4

Related Questions