Nested list-initialization with non-copyable type does not work

Viewed 63
void foo(std::pair<int, std::vector<std::unique_ptr<int>>>&&) {}

foo({{}, {}});

The above does not compile with an error message reporting that it attempts to call into the copy constructor of std::vector<std::unique_ptr<int>> (which is deleted). However, the following works

void foo(std::vector<std::unique_ptr<int>>&&) {}
void foo(const std::vector<std::unique_ptr<int>>&) {}

foo({});

What rules am I missing that make the second example work and the first example not work?


Example: https://wandbox.org/permlink/wE913kQTulV94uDf

1 Answers

It seems I have an answer to my own question -- this does not work because the nested list initialization overload only has the following std::pair constructor to match

pair( const T1& x, const T2& y );

The other std::pair constructor with two arguments is templated without a default type, so it does not get considered

template< class U1, class U2 >
pair( U1&& x, U2&& y );

If we were to change this to a type where the second constructor has default types or has non-templated rvalue overloads, then the above works

template <typename T1, typename T2>
class Pair {
public:
    Pair(const T1&, const T2&) {}
    Pair(T1&&, T2&&) {}
};

void foo(Pair<int, std::vector<std::unique_ptr<int>>>&&) {}

foo({{}, {}});

https://wandbox.org/permlink/pbmme350X7XjM8cI

Or

template <typename T1, typename T2>
class Pair {
public:
    Pair(const T1&, const T2&) {}
    
    template <typename U1 = T1, typename U2 = T2>
    Pair(U1&&, U2&&) {}
};

void foo(Pair<int, std::vector<std::unique_ptr<int>>>&&) {}

foo({{}, {}});

https://wandbox.org/permlink/EuYSJ2n2WTg368YS

Related