请考虑以下代码:
#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;
}
当我尝试构建时,我get(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(
^~~~~~~~~
为什么编译器选择容器类型的空类型包,如果这会导致错误?
答案 0 :(得分:4)
来自list initialization的cppreference:
braced-init-list不是表达式,因此没有类型,例如
decltype({1,2})
格式不正确。没有类型意味着模板类型推导不能推断出与braced-init-list匹配的类型,因此在声明template<class T> void f(T);
的情况下,表达式f({1,2,3})
是不正确的。
为什么编译器为容器类型选择空类型包
由于模板参数包的含义模糊不清,有两种可能的解释方法(我认为)。由于两者都不是格式良好,我不确定标准是否规定哪种解释是正确的。
参数包的大小为1,在这种情况下,单个类型将从格式错误的braced-init-list中推断出来。
或者,由于类型的任何内容都没有超出第一个参数,因此空参数包是Containers
唯一允许的推导类型。现在,由于推导函数只接受一个参数,因此braced-init-list太多了。这就是编译器选择解释的方式。
从根本上说,问题在于您尝试循环扣除。您显然试图从Containers
中推断出类型的内容推断Containers
- 如果它不是空包。
答案 1 :(得分:1)
调用函数时,无法从{}
推断出来。
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} } } );