Title
[fund.ts] optional forwarding construction/assignment
Status
nad
Section
[optional.object.ctor]
Submitter
Cassio Neri

Created on 2013-09-23.00:00:00 last changed 120 months ago

Messages

Date: 2014-06-17.21:17:35

Proposed resolution:

This wording is relative to N3691.

  1. Change [optional.object.ctor] as indicated:

    template <class U, class... Args> 
    constexpr explicit optional(in_place_t, initializer_list<U>&& il, Args&&... args);
    

    -27- Requires: is_constructible<T, initializer_list<U>&&, Args&&...>::value is true.

    -28- Effects: Initializes the contained value as if constructing an object of type T with the arguments ilstd::move(il), std::forward<Args>(args)....

    […]

    -31- Remarks: The function shall not participate in overload resolution unless is_constructible<T, initializer_list<U>&, Args&&...>::value is true.

  2. Change [optional.object.assign] as indicated:

    template <class U, class... Args>
    void optional<T>::emplace(initializer_list<U>&& il, Args&&... args);
    

    -27- Requires: is_constructible<T, initializer_list<U>&&, Args&&...>::value is true.

    -28- Effects: Calls *this = nullopt. Then initializes the contained value as if constructing an object of type T with the arguments ilstd::move(il), std::forward<Args>(args)....

    […]

    -32- Remarks: This function shall not participate in overload resolution unless is_constructible<T, initializer_list<U>&, Args&&...>::value is true.

Date: 2014-06-15.00:00:00

[ 2014-06-17, Rapperswil ]

Move to NAD

Date: 2014-06-06.00:00:00

[ 2014-06-06 pre-Rapperswil ]

This issue has been reopened as fundamentals-ts.

Date: 2014-06-06.21:18:30

Addresses: fund.ts

Consider:

struct foo {
  foo(std::initializer_list<int>&);        // 1
  foo(const std::initializer_list<int>&);  // 2
  foo(std::initializer_list<int>&&);       // 3
  foo(const std::initializer_list<int>&&); // 4
};

std::initializer_list<int> il{0, 1, 2};

foo foo_0{1, 2, 3};                                 // calls 3
foo foo_1{il};                                      // calls 1
foo foo_2((const std::initializer_list<int>&) il);  // calls 2
foo foo_3{(std::initializer_list<int>&&) il};       // calls 3
foo foo_4((const std::initializer_list<int>&&) il); // calls 4

Although the constructors of foo are unusual (initializer_lists are normally passed by value) users of optional could naturally expect perfect forwarding of initializer_lists. However, all lines below end up calling 1.

optional<foo> opt0{in_place, {1, 2, 3}};
optional<foo> opt1{in_place, il};                    
optional<foo> opt3{in_place, (const std::initializer_list<int>&) il};
optional<foo> opt2{in_place, (std::initializer_list<int>&&) il};
optional<foo> opt4{in_place, (const std::initializer_list<int>&&) il};

opt0.emplace({1, 2, 3});
opt0.emplace(il);
opt0.emplace((const std::initializer_list<int>&) il);
opt0.emplace((std::initializer_list<int>&&) il);
opt0.emplace((const std::initializer_list<int>&&) il);

The constructor

template <class... Args> constexpr explicit optional(in_place_t, Args&&... args);

can handle all constructor calls above, except the one taking {1, 2, 3}. Hence, a simple modification of

template <class U, class... Args>
constexpr explicit optional(in_place_t, initializer_list<U>&& il, Args&&... args);

allows perfect forwarding of std::initializer_list<U>s to be complete.

History
Date User Action Args
2014-06-17 21:17:35adminsetmessages: + msg7064
2014-06-17 21:17:35adminsetstatus: open -> nad
2014-06-06 21:18:30adminsetmessages: + msg6997
2014-06-06 21:18:30adminsetstatus: deferred -> open
2013-10-07 20:36:11adminsetmessages: + msg6680
2013-09-23 00:00:00admincreate