Why isn't it possible to make a tuple which contains a tuple and a unique_ptr as values in C++?

Viewed 343

Putting an std::unique_ptr inside an std::tuple works without any issues, but when the tuple contains another tuple together with a unique_ptr as elements, then the compiler throws an error.

Example:

    std::tuple<int, std::unique_ptr<Entity>> tupleA {1, std::move(new Entity)};

    //this line throws an error!
    std::tuple<std::tuple<int, int>, std::unique_ptr<Entity>> tupleB {{1, 1}, std::move(new Entity)};

The second line, creating the `tupleB` is throwing the following error:
        error: no matching constructor for initialization of ´std::tuple<std::tuple<int, int>,std::unique_ptr<Entity>>´
        note: candidate constructor template not viable: cannot convert initializer list argument to ´std::allocator_arg_t´

What exactly is the Problem here?

4 Answers

TL;DR

Change your code so it reads

std::tuple<std::tuple<int, int>, std::unique_ptr<Derived>> tupleB{std::make_tuple(1,1), std::move(new Derived)};

Details

Your compiler tells you what is wrong. It says (MSVC in this case)

error C2440: 'initializing': cannot convert from 'initializer list' to 'std::tuplestd::tuple<int,int,std::unique_ptr<Derived,std::default_delete>>'

So instead of using the initializer list go like this

std::tuple<std::tuple<int, int>, std::unique_ptr<Derived>> tupleB{std::make_tuple(1,1), std::move(new Derived)};

The issue is the following:

When a container is initialized with values within braces, like { 1, 1}, this is deduced to type std::initializer_lists<const char *>. In turn the compiler looks for a container constructor which takes an initializer list as a parameter.

std::forward_as_tuple(1, 1) instead of {1, 1} should work.

you cannot use initializer list to initialize a tuple, you have to use std::make_tuple like below:

std::tuple<std::tuple<int, int>, std::unique_ptr<Entity>> tupleB {std::make_tuple<int, int>(1, 1), std::move(new Entity)};

instead of {1, 1} use std::make_tuple(1, 1)

Related