The following does not compile:
#include <memory>
#include <tuple>
#include <utility>
int main()
{
std::apply(std::make_unique<int>, std::make_tuple(1));
return 0;
}
Error message:
In file included from /usr/include/c++/11/bits/unique_ptr.h:37,
from /usr/include/c++/11/memory:76,
from main.cpp:1:
/usr/include/c++/11/tuple: In instantiation of ‘constexpr decltype(auto) std::__apply_impl(_Fn&&, _Tuple&&, std::index_sequence<_Idx ...>) [with _Fn = std::unique_ptr<int, std::default_delete<int> > (&)(); _Tuple = std::tuple<int>; long unsigned int ..._Idx = {0}; std::index_sequence<_Idx ...> = std::integer_sequence<long unsigned int, 0>]’:
/usr/include/c++/11/tuple:1869:31: required from ‘constexpr decltype(auto) std::apply(_Fn&&, _Tuple&&) [with _Fn = std::unique_ptr<int, std::default_delete<int> > (&)(); _Tuple = std::tuple<int>]’
main.cpp:7:15: required from here
/usr/include/c++/11/tuple:1858:27: error: no matching function for call to ‘__invoke(std::unique_ptr > (&)(), std::__tuple_element_t<0, std::tuple >)’
1858 | return std::__invoke(std::forward<_Fn>(__f),
| ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
1859 | std::get<_Idx>(std::forward<_Tuple>(__t))...);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/11/tuple:41,
from /usr/include/c++/11/bits/unique_ptr.h:37,
from /usr/include/c++/11/memory:76,
from main.cpp:1:
/usr/include/c++/11/bits/invoke.h:90:5: note: candidate: ‘template constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _Args&& ...)’
90 | __invoke(_Callable&& __fn, _Args&&... __args)
| ^~~~~~~~
/usr/include/c++/11/bits/invoke.h:90:5: note: template argument deduction/substitution failed:
/usr/include/c++/11/bits/invoke.h: In substitution of ‘template<class _Callable, class ... _Args> constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _Args&& ...) [with _Callable = std::unique_ptr<int, std::default_delete<int> > (&)(); _Args = {int}]’:
/usr/include/c++/11/tuple:1858:27: required from ‘constexpr decltype(auto) std::__apply_impl(_Fn&&, _Tuple&&, std::index_sequence<_Idx ...>) [with _Fn = std::unique_ptr<int, std::default_delete<int> > (&)(); _Tuple = std::tuple<int>; long unsigned int ..._Idx = {0}; std::index_sequence<_Idx ...> = std::integer_sequence<long unsigned int, 0>]’
/usr/include/c++/11/tuple:1869:31: required from ‘constexpr decltype(auto) std::apply(_Fn&&, _Tuple&&) [with _Fn = std::unique_ptr<int, std::default_delete<int> > (&)(); _Tuple = std::tuple<int>]’
main.cpp:7:15: required from here
/usr/include/c++/11/bits/invoke.h:90:5: error: no type named ‘type’ in ‘struct std::__invoke_result > (&)(), int>’
How can this be fixed?
C++17 and earlier
std::make_unique<int>
has the type std::unique_ptr<int>()
which is a function that returns a std::unique_ptr<int>
and takes no parameters. That is not what you want since you are passing a value to the function.
What you need is std::make_unique<int, int>
which has the type std::unique_ptr<int>(int)
which is what you want. The first template parameter is for the type of the unique_ptr
and each additional type is for the argument types of the make function.
C++20+
Since C++20 make_unique
is not an addressable function so you are no longer allowed to use this technique in portable code. Instead you'll need to leverage a lambda for a level of indirection like
std::apply([](auto&& var){ return std::make_unique<int>(decltype(var)(var)); }, std::make_tuple(1));