std::array作为重载函数参数出现二义性的原因咨询
问题:为什么std::array重载函数调用出现二义性?
我想让编译器根据数组大小选择对应的重载函数,其中funct({1,2,3})能正常工作,但funct({1,2})和funct({1})都报二义性错误。std::array<int,1>、std::array<int,2>、std::array<int,3>明明是不同的数据类型,为什么会这样?
我的代码
#include<iostream> #include<array> using namespace std; void funct(array<int,1> one) { cout<<"one"<<endl; } void funct(array<int,2> two) { cout<<"two"<<endl; } void funct(array<int,3> three) { cout<<"three"<<endl; } int main() { funct({1,2,3}); funct({1,2}); funct({1}); return 0; }
编译错误信息
||=== Build: Debug in ambiguitytest (compiler: GNU GCC Compiler) ===| [redacted]\ambiguitytest\main.cpp||In function 'int main()':| [redacted]\ambiguitytest\main.cpp|19|error: call of overloaded 'funct(<brace-enclosed initializer list>)' is ambiguous| [redacted]\ambiguitytest\main.cpp|8|note: candidate: void funct(std::array<int, 2u>)| [redacted]\ambiguitytest\main.cpp|12|note: candidate: void funct(std::array<int, 3u>)| [redacted]\ambiguitytest\main.cpp|20|error: call of overloaded 'funct(<brace-enclosed initializer list>)' is ambiguous| [redacted]\ambiguitytest\main.cpp|4|note: candidate: void funct(std::array<int, 1u>)| [redacted]\ambiguitytest\main.cpp|8|note: candidate: void funct(std::array<int, 2u>)| [redacted]\ambiguitytest\main.cpp|12|note: candidate: void funct(std::array<int, 3u>)| ||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
原因分析与解决办法
核心原因
std::array<T, N>是聚合类型,它支持用长度小于等于N的初始化列表来构造——如果初始化列表的元素数量比N少,剩下的元素会被自动值初始化(这里就是填充0)。
- 对于
funct({1,2,3}):只有std::array<int,3>能匹配,因为std::array<int,1>和std::array<int,2>的大小小于初始化列表的长度,聚合初始化不允许元素数量超过数组大小,所以编译器只能选择第三个重载,不会有冲突。 - 对于
funct({1,2}):这个初始化列表既可以构造std::array<int,2>(刚好填满),也可以构造std::array<int,3>(剩下一个元素填0),这两个构造都是合法的,编译器无法判断哪个是你想要的,所以报二义性错误。 - 对于
funct({1}):同理,这个列表能构造std::array<int,1>、std::array<int,2>、std::array<int,3>三个类型,三个重载都匹配,自然冲突。
解决办法
办法一:显式指定类型
调用时直接明确构造对应的std::array类型,消除歧义:
funct(array<int,3>{1,2,3}); funct(array<int,2>{1,2}); funct(array<int,1>{1});
办法二:改用模板函数替代重载
用模板函数推导数组大小,再通过编译期分支处理不同情况,避免重载冲突:
#include<iostream> #include<array> using namespace std; template<size_t N> void funct(array<int, N> arr) { if constexpr (N == 1) { cout << "one" << endl; } else if constexpr (N == 2) { cout << "two" << endl; } else if constexpr (N == 3) { cout << "three" << endl; } } int main() { funct({1,2,3}); funct({1,2}); funct({1}); return 0; }
这里if constexpr是C++17及以上的特性,能在编译期完成分支判断,不会产生运行时开销。
内容的提问来源于stack exchange,提问作者IAHSXIDEAS
相关产品推荐
相关产品推荐

