可变参数模板不适用于初始值设定项列表
Variadic template not working with an initializer list
我创建了一个工厂函数模板:
template <typename M, typename... Args>
std::shared_ptr<M> create(Args... args)
{
return std::make_shared<M>(args...);
}
还有一个简单的容器:
struct Group {
std::vector<int> vec;
Group(std::initializer_list<int> il) : vec(il) {}
};
然后我尝试创建一个组
int main()
{
auto gr = create<Group>({1, 2, 3});
return 0;
}
这不编译,
error: no matching function for call to 'create'
auto gr = create<Group>({1, 2, 3});
candidate function not viable: requires 0 arguments, but 1 was provided
std::shared_ptr<M> create(Args... args)
^
但是如果我使用临时变量:
int main(int argc, char *argv[])
{
std::initializer_list<int> il = {1, 2, 3};
auto gr = create<Group>(il);
return 0;
}
确实如此。为什么?
对于这种情况,推荐的解决方案是什么?
模板参数不能从初始值设定项列表(它是非推导的上下文)中推导,但可以从类型为std::initializer_list<something>
的表达式中推导。两者是不一样的。
[temp.deduct.call]/1模板参数推导是通过将每个函数模板参数类型(调用它
P
)与调用的相应参数的类型(调用它A
)进行比较来完成的,如下所述。如果从P
中删除引用和 cv 限定符会为某些P'
提供std::initializer_list<P'>
,并且参数是初始值设定项列表 (8.5.4),则改为对初始值设定项列表中的每个元素执行推导,将P'
作为函数模板参数类型,将初始值设定项元素作为其参数。否则,初始值设定项列表参数会导致参数被视为非推导上下文 (14.8.2.5)。[示例:template<class T> void f(std::initializer_list<T>); f({1,2,3}); // T deduced to int f({1,"asdf"}); // error: T deduced to both int and const char* template<class T> void g(T); g({1,2,3}); // error: no argument deduced for T
—结束示例]
来自 cpp首选项:
大括号的初始化列表不是表达式,因此没有类型,例如
decltype({1,2})
格式不正确。没有类型意味着模板类型推导无法推断出与大括号初始化列表匹配的类型,因此给定声明template<class T> void f(T);
表达式f({1,2,3})
格式不正确。
但有一个例外:auto a = { 1, 2 };
导致a
成为std::initializer_list
。但这仅在auto
类型推断中,不适用于模板。
相关文章:
- FLTK 2.0构建和演示,适用于VS2019的2011年左右的代码库
- C++17 - 使用自定义分配器的节点提取/重新插入 - 适用于 clang++/libc++,但不适用于 libstd
- "string.h"在构建适用于iOS的qt应用程序中找不到消息
- 适用于 WebView2 旧版本的示例应用程序
- 在 NVIDIA GEFORCE GTX 1050 上下载适用于 Windows 10 的 openCL 1.2
- 嵌套列表,用于在 C++ 中实现邻接列表
- __attribute__(优化(0))) 是否适用于"recursively"?
- 为什么 std::erase(std::erase_if) 不是适用于<algorithm>任何容器的模板?
- 使用一个参数的模板函数时出错(适用于 2)
- 使用 适用于 Android 和 iOS 的 tf-lite C++ API
- 为什么这适用于 G++ 而不是 CLANG?
- 适用于 macOS 的 Xcode 应用程序。这就是我设置从USB麦克风输入获取音频的方式。一年前工作,现在没有了。为什么
- 适用于 Linux 的 c++ 上的代理脚本
- 为什么我的 SFINAE 表达式不再适用于 GCC 8.2?
- 使输出流式处理运算符适用于 boost::variant<std::vector<int>、int、double 的正确方法是什么>
- 有没有适用于Windows.lib文件的GNU二进制文件描述符(BFD)
- 模板函数仅适用于VS
- 如何在cmake中包含适用于g++或viceversa的库
- 警告:扩展初始值设定项列表仅适用于-std=c++0x或-std=gnu++0x
- 警告:扩展初始化器列表仅适用于STD c++ 11