Search code examples
c++pointersstlunique-ptrstdtuple

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


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?


Solution

  • 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.