如何将模板构造函数的Args参数传递给deque.emplace_back?
通用Collection构造函数编译失败的解决办法
问题背景
尝试编写通用构造函数,将模板参数Args传递给std::deque<std::any>的emplace_back(),期望创建可容纳不同类型、不同数量Entry的Collection实例,但代码编译失败。
原代码
class Collection { public: template <typename ...Args> Collection(const std::string& name, Args... entries) : m_name(name) { m_entries.emplace_back(entries...); // 期望将Entry<int>、Entry<double>、Entry<int, int>添加到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} };
编译错误信息
/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)...); } | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
问题原因
原代码中m_entries.emplace_back(entries...)的写法错误:它试图将所有Entry类型参数一次性传递给单个std::any的构造函数,但std::any只能存储单个任意类型的值,无法同时接受多个参数构造。
解决方案
需要逐个处理每个模板参数,将每个Entry单独构造为std::any并添加到deque中。使用C++17的折叠表达式可以简洁实现这一点,同时通过std::forward实现完美转发,避免不必要的拷贝:
修正后的代码
#include <any> #include <deque> #include <string> #include <utility> // 假设Entry和Entry2的定义如下 template <typename T> struct Entry { T value; }; template <typename T1, typename T2> struct Entry2 { T1 a; T2 b; }; class Collection { public: template <typename ...Args> Collection(const std::string& name, Args&&... entries) : m_name(name) { // 使用折叠表达式逐个emplace_back每个Entry (m_entries.emplace_back(std::forward<Args>(entries)), ...); } 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} };
关键说明
- 折叠表达式:
(m_entries.emplace_back(...), ...)会展开为对每个entries参数调用一次emplace_back,例如:m_entries.emplace_back(std::forward<Entry<int>>(entries_1)); m_entries.emplace_back(std::forward<Entry<double>>(entries_2)); m_entries.emplace_back(std::forward<Entry2<int,int>>(entries_3)); - 完美转发:
std::forward<Args>(entries)保留参数的左值/右值属性,避免不必要的对象拷贝,提升效率。
内容的提问来源于stack exchange,提问作者user3124812
相关产品推荐
相关产品推荐

