Add move constructor and operator [] for std::initializer_list

119 views
Skip to first unread message

NDos Dannyu

unread,
Nov 27, 2016, 11:18:35 PM11/27/16
to ISO C++ Standard - Future Proposals
 First, most standard containers' operator = and assign can take std::initializer_list and assign its elements.
But std::initializer_list only has the default constructor, neither copy constructor nor move constructor.
So, I have to write identical code within their operator = and assign, which seems unnecessary.
If std::initializer_list had move constructor, I could implement operator = like this:
template <class T, class Alloc> std::deque<T, Alloc> &std::deque<T, Alloc>::operator = (std::initializer_list<T> ilist) {
    assign(std::move(ilist));
    return *this;
}
So, I request to add move constructor for std::initializer_list.
 Second, because std::initializer_list doesn't have operator [], I have to access the initializer list by index like this:
    (an initializer list).begin()[(index)]
Which seems unnecessary. So, I request to add operator [] for std::initializer_list.

Thiago Macieira

unread,
Nov 28, 2016, 12:38:31 AM11/28/16
to std-pr...@isocpp.org
On domingo, 27 de novembro de 2016 20:18:35 PST NDos Dannyu wrote:
> So, I request to add move constructor for *std::initializer_list*.

Can't be done, because std::initializer_list does not own the elements it
points to. Its lifetime cannot be extended.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center

D. B.

unread,
Nov 28, 2016, 1:45:20 AM11/28/16
to std-pr...@isocpp.org
Maybe I'm missing it, but why would moving be of any use in that scenario? Can you explain?

I'm also curious about cases where operator[] would be needed. Every time I find myself wanting it, I seem to end up improving my design so it's not necessary or applicable. initializer_list is meant for initialisation, not as a radom-access sequence.

D. B.

unread,
Nov 28, 2016, 1:56:07 AM11/28/16
to std-pr...@isocpp.org
On Mon, Nov 28, 2016 at 6:45 AM, D. B. <db0...@gmail.com> wrote:
Maybe I'm missing it, but why would moving be of any use in that scenario? Can you explain?


To be clearer, by my understanding, since initializer_list is just a cheap copy-only view of an array, moving (A) doesn't make sense and (B) would not make any difference to efficiency anyway. So I see no problem with passing by value from operator=() to assign(). Does this not work somehow? This does for me:

#include <initializer_list>
#include <iostream>

void f(std::initializer_list<char> const il)
{
        for (auto const it: il) {
                std::cout << it << std::endl;
        }
}

void g(std::initializer_list<char> const il)
{
        f(il);
}

int main()
{
        g( {'H', 'E', 'L', 'L', 'O'} );
}

NDos Dannyu

unread,
Nov 28, 2016, 2:42:07 AM11/28/16
to ISO C++ Standard - Future Proposals


2016년 11월 28일 월요일 오후 3시 56분 7초 UTC+9, D. B. 님의 말:
On Mon, Nov 28, 2016 at 6:45 AM, D. B. <db0...@gmail.com> wrote:
Maybe I'm missing it, but why would moving be of any use in that scenario? Can you explain?


To be clearer, by my understanding, since initializer_list is just a cheap copy-only view of an array, moving (A) doesn't make sense and (B) would not make any difference to efficiency anyway. So I see no problem with passing by value from operator=() to assign(). Does this not work somehow? This does for me:
As said, std::initializer_list has neither copy constructor nor move constructor. Your code assumes std::initializer_list has copy constructor, which it doesn't in the standard.

I used operator [] like this, in implementation of std::deque::assign:
        void assign(std::initializer_list<T> other) {
            if (other.size() <= size()) {
                std::move(other.begin(), other.end(), begin());
                erase(cbegin() + other.size(), cend());
                ce = cb + other.size();
            } else if (other.size() <= ce - ab) {
                std::for_each(ce - other.size(), cb, [&](pointer &p){
                    p = vatraits::allocate(va, 1);
                    vatraits::construct(va, p, std::move(other.begin()[&p - (ce - other.size())]));
                });
                std::move(other.end() - size(), other.end(), begin());
                cb = ce - other.size();
            } else if (other.size() <= ae - ab) {
                auto newE = [&](pointer &p){
                    p = vatraits::allocate(va, 1);
                    vatraits::construct(va, p, std::move(other.begin()[&p - ab]));
                };
                std::for_each(ab, cb, newE);
                std::move(other.begin() + (cb - ab), other.begin() + (ce - ab), begin());
                std::for_each(ce, ab + other.size(), newE);
                cb = ab;
                ce = ab + other.size();
            } else {
                pointer *nab = new pointer[other.size() << 1], *ncb = nab + (other.size() >> 1);
                std::for_each(ncb, ncb + size(), [&](pointer &p){
                    p = cb[&p - ncb];
                    *p = std::move(other.begin()[&p - ncb]);
                });
                std::for_each(ncb + size(), ncb + other.size(), [&](pointer &p){
                    p = vatraits::allocate(va, 1);
                    vatraits::construct(va, p, std::move(other.begin()[&p - ncb]));
                });
                cb = ncb;
                ce = ncb + other.size();
                delete []ab;
                ab = nab;
                ae = nab + (size() << 1);
            }
        }

D. B.

unread,
Nov 28, 2016, 3:09:06 AM11/28/16
to std-pr...@isocpp.org
I'm pretty sure passing initializer_list by value is defined,
but even if not, just pass it by reference then.
It still doesn't need to be movable in any case.

D. B.

unread,
Nov 28, 2016, 3:10:56 AM11/28/16
to std-pr...@isocpp.org
I mean, you said initializer_list has no copy constructor, but it should have a default copy constructor, which simply copies the contained begin/end pointers (or begin + size, doesn't matter). Likewise move should do the same thing, unless it's =deleted. Not that it matters, again.

NDos Dannyu

unread,
Nov 28, 2016, 3:24:54 AM11/28/16
to ISO C++ Standard - Future Proposals


2016년 11월 28일 월요일 오후 5시 10분 56초 UTC+9, D. B. 님의 말:
I mean, you said initializer_list has no copy constructor, but it should have a default copy constructor, which simply copies the contained begin/end pointers (or begin + size, doesn't matter). Likewise move should do the same thing, unless it's =deleted. Not that it matters, again.

Oh, it implicitly does, as well as the move constructor. I didn't exactly know when the special member functions are implicitly defined, sorry.
Then, what about operator []?

D. B.

unread,
Nov 28, 2016, 3:30:02 AM11/28/16
to std-pr...@isocpp.org
operator[] is never implicitly defined. As for your example about where it would be useful, I'd need to take some time to comprehend that. :D

NDos Dannyu

unread,
Nov 28, 2016, 3:36:17 AM11/28/16
to ISO C++ Standard - Future Proposals


2016년 11월 28일 월요일 오후 5시 30분 2초 UTC+9, D. B. 님의 말:
operator[] is never implicitly defined. As for your example about where it would be useful, I'd need to take some time to comprehend that. :D
 I asked whether it is needed, though.

Here is the entire code:

rick...@hotmail.com

unread,
Dec 5, 2016, 5:53:54 PM12/5/16
to ISO C++ Standard - Future Proposals
As welll as missing operator [], std::initializer_list also lacks the relational operators. I think they should be added also.

Daniel Boles

unread,
Dec 5, 2016, 6:01:36 PM12/5/16
to std-pr...@isocpp.org
Can you provide a convincing use case for relational operators on
std::initializer_list? operator[] kinda makes sense at a push, but I'm
not sure about anything more elaborate.

Richard Smith

unread,
Dec 5, 2016, 6:15:15 PM12/5/16
to std-pr...@isocpp.org
On 5 December 2016 at 14:53, <rick...@hotmail.com> wrote:
As welll as missing operator [], std::initializer_list also lacks the relational operators. I think they should be added also.

Why? initializer_list is just a vehicle for shipping a homogeneous initializer's value into your constructor. It is not a container.

Thiago Macieira

unread,
Dec 5, 2016, 6:53:38 PM12/5/16
to std-pr...@isocpp.org
Em segunda-feira, 5 de dezembro de 2016, às 14:53:53 PST, rick...@hotmail.com
escreveu:
> As welll as missing operator [], std::initializer_list also lacks the
> relational operators. I think they should be added also.

operator[] is unnecessary, since you can do begin()[n].

Why should it have relational operators? What if the type it's initialising
has no concept of ordering?
Reply all
Reply to author
Forward
0 new messages