为什么我的初始值设定项列表在类型推断中被半忽略?

Why is my initializer list semi-ignored for type deduction?

本文关键字:类型 我的 列表 为什么      更新时间:2023-10-16

请考虑以下代码:

#include <unordered_map>
#include <iostream>
#include <vector>
template <typename Container, typename... Containers>
inline Container get_union(
const Container& c1,
const Containers&... more_containers)
{
Container result(c1);
auto f = [&result](const Container& c) {
result.insert(std::begin(c), std::end(c)); 
};
[](...){}(( f(more_containers), 0)...);
return result;
}
int main()
{
std::unordered_map<int, int> m1 = { {1, 2}, {3, 4} };
decltype(m1) m2 = get_union(m1, { {5, 6}, {7, 8} } );
std::cout << "m2.size() = " << m2.size() << "n'";
return 0;
}

当我尝试构建它时,我得到(coliru 链接):

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp: In function 'int main()':
main.cpp:21:56: error: too many arguments to function 'Container get_union(const Container&, const Containers& ...) [with Container = std::unordered_map<int, int>; Containers = {}]'
decltype(m1) m2 = get_union(m1, { {5, 6}, {7, 8} } );
^
main.cpp:6:18: note: declared here
inline Container get_union(
^~~~~~~~~

如果编译器为容器类型选择空类型包,为什么这会导致错误?

引用cpp首选项上的列表初始化:

大括号的初始化列表不是表达式,因此没有类型,例如decltype({1,2})格式不正确。没有类型意味着模板类型推导无法推断出与大括号初始化列表匹配的类型,因此给定声明template<class T> void f(T);表达式f({1,2,3})格式不正确。


为什么编译器为容器类型选择空类型包

由于模板参数包可能模棱两可,有两种可能的方式可以解释(我认为)。由于两者都不是格式良好的,我不确定标准是否决定了哪种解释是正确的。

  • 要么参数包的大小为 1,在这种情况下,将从格式错误的大括号初始化列表中推断出单个类型。

  • 或者,由于在第一个参数之外没有传递任何类型,因此空参数包是Containers唯一可能的推导类型。现在,由于推导函数只接受单个参数,因此大括号的初始化列表太多了。这就是编译器选择解释的方式。

从根本上说,问题在于您正在尝试循环演绎。你显然试图从某种东西中推断出Containers,如果它不是一个空包,那么这种东西的类型可以从任何Containers中推断出来。

调用函数时无法从{}推断。

template <typename Container, typename... Containers>
inline Container get_union(
Container c1,
std::initializer_list<Container> more_containers)
{
for (auto&& c:more_containers)
c1.insert( std::begin(c), std::end(c) );
return c1;
}

然后像这样调用:

auto m2 = get_union(m1, { { {5, 6}, {7, 8} } } );

现场示例

相关文章: