How to use second overload of std::optional<T>::emplace
Asked Answered
L

1

5

In the std::optional::emplace docs there is an overload that accepts std::initializer_list:

template< class U, class... Args >
T& emplace( std::initializer_list<U> ilist, Args&&... args );

provided that

std::is_constructible<T, std::initializer_list&, Args&&...>::value is true

I thought that it might be used to emplace POD types, but apparently this is not how it works (in other SO topics it was explained that emplace functions are using () syntax instead of {}):

struct A
{
    int x;
    int y;
    int z;
};
int main()
{
    A normalA{1, 2, 3};  // this is OK
    std::cout << std::is_constructible<A, std::initializer_list<int>&, int, int, int>::value << std::endl;  // false
    std::cout << std::is_constructible<A, std::initializer_list<int>&>::value << std::endl;  // false
    std::optional<A> optA;
    // optA.emplace({1, 2, 3});  // this is NOK
    optA.emplace(A{1, 2, 3});  // I can walk it around with copy-ctor
}

I can write the constructor accepting initializer_list:

struct B
{
    B(std::initializer_list<int> l) {/* some impl here */}
    int x;
    int y;
    int z;
};

and then call emplace like this:

    std::optional<B> optB;
    optB.emplace({1, 2, 3});

but shouldn't first emplace overload T& emplace( Args&&... args ); be enough for that? I thought that it might be useful for the array types, but std::optional<int[]> xxx; does not compile anyway.

Can you please provide some example where second std::optional::emplace overload is used.

Luminal answered 9/6, 2021 at 14:57 Comment(1)
Probably to make emplace({1,2,3}, allocator); work for optional<vector<int>>. Even without the allocator argument the overload is required.Freya
V
6

but shouldn't first emplace overload T& emplace( Args&&... args ); be enough for that?

It isn't because a braced-init-list, i.e. {1, 2, 3} has no type. Because it has no type, there is nothing to compiler can do to deduce what Args should be. We need to have an overload that explicitly takes a std::initializer_list so that we can avoid the compiler not being able to deduce what the braced-init-list should be considered as.

Vying answered 9/6, 2021 at 15:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.