我正在尝试将Args
参数从模板传递到容器deque.emplace_back()
调用
例如
class Collection
{
public:
template <typename ...Args>
Collection(const std::string& name, Args... entries)
: m_name(name)
{
m_entries.emplace_back(entries...); // Here!!!! Entry<int>, Entry<double>, Entry<int, int> added to deque
}
private:
std::string m_name;
std::deque<std::any> m_entries;
};
Collection collection1
{
"my collection",
Entry<int>{4},
Entry<double>{5.5},
Entry2<int, int>{1, 2}
};
基本上我想要有多个“Collection”实例,具有不同的“Entry”集(不同类型,不同数字)。并希望为所有可能的组合创建通用构造函数。
emplace_back
是带有Args
参数重载的模板
template< class... Args >
reference emplace_back( Args&&... args );
所以我认为它可能需要一个对象列表。但这还没有编译。有错误
/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 = std::any; _Args = {Entry<int>&, Entry<double>&, Entry2<int, int>&}; _Tp = std::any]':
/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 = std::any; _Args = {Entry<int>&, Entry<double>&, Entry2<int, int>&}; _Tp = std::any; allocator_type = std::allocator<std::any>]'
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bits/deque.tcc:170:30: required from 'std::deque<_Tp, _Alloc>::reference std::deque<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {Entry<int>&, Entry<double>&, Entry2<int, int>&}; _Tp = std::any; _Alloc = std::allocator<std::any>; reference = std::any&]'
<source>:44:31: required from 'Collection::Collection(const std::string&, Args ...) [with Args = {Entry<int>, Entry<double>, Entry2<int, int>}; std::string = std::__cxx11::basic_string<char>]'
<source>:58:1: 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 'std::any::any(Entry<int>&, Entry<double>&, Entry2<int, int>&)'
187 | { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Godbolt 的完整示例 https://godbolt.org/z/YoPPToEdr
我很乐意提供如何完成这项工作的建议。
谢谢
您实际上不想
emplace_back
在此处使用,因为它将呈几何级数增长,并且当您将元素添加到deque
. 相反,您想要做的是deque
像初始化成员一样直接初始化类成员初始值设定项列表中的string
。这会给你:请注意,我们使用
{}
in 是m_entries{args...}
因为我们想要列出初始化,并且为此使用了大括号。如果您确实需要调用函数,那么执行此操作的方法是
这称为一元折叠表达式,语法是
( expression_using_pack op ...)
或(... op expression_using_pack)
取决于您分别进行右折叠还是左折叠。这里我们使用逗号运算符来展开包,因为该运算符允许我们按顺序处理表达式,而无需执行任何其他操作。注释与代码不符。来自cppreference.com 上的文档
std::deque::emplace_back
:这是一个新元素,单数,而不是复数。如果调用
emplace_back
一次,无论提供多少个参数,都会添加一个新元素。(支持多个参数,因为某些构造函数采用多个参数。)相比之下,注释说要添加三个元素。要获得三个新元素,您需要调用
emplace_back
三次。您的语法很接近,但您的包扩展entries
中只有. 您的代码扩展为它尝试从三个参数构造单个元素,类似于
collection1
从四个参数构造变量的方式。如果您要包含m_entries.emplace_back
在扩展中,您将收到多次调用。扩展为(为了可读性添加了换行符)
三次调用
emplace_back
,因此三个元素被添加到双端队列中。请注意最外面的括号,因为折叠表达式语法需要这些括号才能工作。(话虽这么说,直接初始化双端队列是更好的选择,因为这会将更多的工作推到实现上,并且实现应该知道处理数据的最佳方式。)