I am trying to emplace a new object into a container inside a template function. Since the template function receives an std::tuple with the arguments needed to create the object, I am using std::apply and a fold expression to unpack the tuple values. However, it doesn't compile
My code is equivalent to
#include <vector>
struct S
{
S(float restAngle, bool useIt)
: restAngle(restAngle)
, useIt(useIt)
{}
float restAngle;
bool useIt;
};
int main()
{
std::tuple t(0.0F, false);
std::vector<S> ss;
std::apply([&ss](auto ...data) {ss.emplace_back((data,...));}, t);
}
and it fails with the following compilation error in gcc 13
n file included from /opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/x86_64-linux-gnu/bits/c++allocator.h:33,
from /opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bits/allocator.h:46,
from /opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/vector:63,
from <source>:1:
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bits/new_allocator.h: In instantiation of 'void std::__new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = S; _Args = {bool&}; _Tp = S]':
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bits/alloc_traits.h:537:17: required from 'static void std::allocator_traits<std::allocator<_Tp1> >::construct(allocator_type&, _Up*, _Args&& ...) [with _Up = S; _Args = {bool&}; _Tp = S; allocator_type = std::allocator<S>]'
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bits/vector.tcc:117:30: required from 'std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {bool&}; _Tp = S; _Alloc = std::allocator<S>; reference = S&]'
<source>:18:52: required from 'main()::<lambda(auto:1 ...)> [with auto:1 = {float, bool}]'
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/type_traits:2558:26: required by substitution of 'template<class _Fn, class ... _Args> static std::__result_of_success<decltype (declval<_Fn>()((declval<_Args>)()...)), std::__invoke_other> std::__result_of_other_impl::_S_test(int) [with _Fn = main()::<lambda(auto:1 ...)>; _Args = {float&, bool&}]'
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/type_traits:2569:55: [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/type_traits:161:35: recursively required by substitution of 'template<class _Result, class _Ret> struct std::__is_invocable_impl<_Result, _Ret, true, std::__void_t<typename _CTp::type> > [with _Result = std::__invoke_result<main()::<lambda(auto:1 ...)>, float&, bool&>; _Ret = void]'
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/type_traits:161:35: required by substitution of 'template<class ... _Bn> std::__detail::__first_t<std::integral_constant<bool, true>, typename std::enable_if<(bool)(_Bn::value), void>::type ...> std::__detail::__and_fn(int) [with _Bn = {std::__is_invocable_impl<std::__invoke_result<main()::<lambda(auto:1 ...)>, float&, bool&>, void, true, void>, std::__call_is_nothrow<std::__invoke_result<main()::<lambda(auto:1 ...)>, float&, bool&>, main()::<lambda(auto:1 ...)>, float&, bool&>}]'
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/type_traits:177:42: required from 'struct std::__and_<std::__is_invocable_impl<std::__invoke_result<main()::<lambda(auto:1 ...)>, float&, bool&>, void, true, void>, std::__call_is_nothrow<std::__invoke_result<main()::<lambda(auto:1 ...)>, float&, bool&>, main()::<lambda(auto:1 ...)>, float&, bool&> >'
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/type_traits:3103:12: required from 'struct std::is_nothrow_invocable<main()::<lambda(auto:1 ...)>, float&, bool&>'
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/tuple:2272:31: required from 'constexpr const bool std::__unpack_std_tuple<template<class _Fn, class ... _ArgTypes> struct std::is_nothrow_invocable, main()::<lambda(auto:1 ...)>, std::tuple<float, bool>&>'
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/tuple:2295:14: required from 'constexpr decltype(auto) std::apply(_Fn&&, _Tuple&&) [with _Fn = main()::<lambda(auto:1 ...)>; _Tuple = tuple<float, bool>&]'
<source>:18:15: required from here
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bits/new_allocator.h:187:11: error: no matching function for call to 'S::S(bool&)'
187 | { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:5:5: note: candidate: 'S::S(float, bool)'
5 | S(float restAngle, bool useIt)
| ^
<source>:5:5: note: candidate expects 2 arguments, 1 provided
<source>:3:8: note: candidate: 'constexpr S::S(const S&)'
3 | struct S
| ^
<source>:3:8: note: no known conversion for argument 1 from 'bool' to 'const S&'
<source>:3:8: note: candidate: 'constexpr S::S(S&&)'
<source>:3:8: note: no known conversion for argument 1 from 'bool' to 'S&&'
I can't find what is wrong with the code. Apparently is trying to call the emplace_back with just the bool arguments, which I don't understand. What is wrong with the code?
You have the syntax a little off. In
You are using a fold expression of the comma operator on the pack of
dataso it expands out toand since it is the comma operator only
dataNis returned from the inner parentheses which in your case is theboolobject of the tuple. To get all of the pack in the call toemplace_backyou just needwhich expands to
which is how the call to
emplace_backshould look like.