调用重载的"<大括号括起来的初始值设定项列表>"对于对来说就足够了是模棱两可的
call of overloaded ‘<brace-enclosed initializer list>’ with suffices for pairs is ambiguous
我无法编译以下代码。
void print_number(long n) {
std::cout << n << std::endl;
}
void print_number(float n) {
std::cout << n << std::endl;
}
void print_pair(std::pair<std::string, long> p) {
std::cout << std::get<1>(p) << std::endl;
}
void print_pair(std::pair<std::string, float> p) {
std::cout << std::get<1>(p) << std::endl;
}
int main() {
print_number(12l);
print_number(3.4f);
print_pair({"long", 12l});
print_pair({"float", 3.4f});
return 0;
}
print_number
函数运行良好。但是,编译器抱怨print_pair
函数过载:error: call of overloaded ‘print_pair(<brace-enclosed initializer list>)’ is ambiguous
.
<brace-enclosed initializer list>
就足够了还是std::pair
不起作用?如何重载接收std::pair
参数的函数?
Tl;博士
为了解决歧义,您可以向编译器提供正确的类型:
print_pair(std::make_pair<std::string, long>("long", 12l));
print_pair(std::make_pair<std::string, float>("float", 3.4f));
或
print_pair(std::make_pair(std::string("long"), 12l));
print_pair(std::make_pair(std::string("float"), 3.4f));
歧义问题源于"long"
和"float"
不是std::string
,而是const char[]
。
所以当你尝试使用以下表达式构造std::pair
时:std::pair{"long", 12l}
,你得到的是一个std::pair<const char[5], long>
。
(浮点数相同;即std::pair<const char[5], float>
(。
您的过载print_pair
接受std::pair<std::string, long>
或std::pair<std::string, float>
。前面的类型都不匹配,因此编译器必须执行转换。因此,它无法自动扣除您要执行的转换。两者都有效。
例如:
std::pair<const char[5], long>
|
----------------------------------------------------------------
v v
std::pair<std::string, long> std::pair<std::string, float>
要"证明"问题是std::string
(既不是long
也不是float
(,也可以解决构造一个适当的std::string
(而不是char
数组(的歧义:
print_pair(std::make_pair(std::string("long"), 12l));
print_pair(std::make_pair(std::string("float"), 3.4f));
从C++17开始,此样板可以简化为:
using namespace std::string_literals;
print_pair(std::pair{"long"s, 12l});
print_pair(std::pair{"float"s, 3.4f});
对于print_pair({"long", 12l});
,有 2 种可能的重载:
void print_pair(std::pair<std::string, long>)
void print_pair(std::pair<std::string, float>)
{"long", 12l}
没有类型,但对std::pair<std::string, long>
和std::pair<std::string, long>
都是有效的初始化。
所以这个电话是模棱两可的。
print_pair(std::pair{"long", 12l});
也是模棱两可的
,因为std::pair<const char*, long>
同样可以转换为std::pair<std::string, long>
和std::pair<std::string, long>
。
你必须称它为:
print_pair(std::pair{std::string("long"), 12l});
完全匹配。
C++的重载解析逻辑不考虑分段转换,它只考虑给定参数/参数对的整个转换。
通过此调用:
print_pair({"long", 12l});
我们有两个可行的候选人。一个候选人参加std::pair<std::string, long>
,另一个候选人参加std::pair<std::string, float>
。
C++没有做的(以及你可能认为它做的(是分别考虑这些部分 - 并说好吧,"long"
std::string
在两种情况下是相同的,但12l
long
比12l
float
更好,因此转换为pair<string, long>
获胜。如果我们有两个接受两个参数的函数,而不是两个需要pair
s 的函数,那么它将是这样工作的:
print_two("long", 12l); // calls print_two(string, long)
但C++不是那样工作的。它所做的是将这些部分放在一起考虑。该大括号初始化列表可用于构建std::pair
专业化。两者都是可行的。两者都是用户定义的转换。两者都不比另一个好,因此模棱两可。我们真的没有语言中的机制来使这种分段转换起作用。
你必须要么说出你的意思:
print_pair(std::pair<std::string, long>("long", 12l));
或者采取两个论点。
感谢您的所有回答。我投了全部赞成票,但是,我想做的是将函数称为具有异构<brace-enclosed initializer list>
的函数print_pair
。
我最终做的是:
struct number {
number(long n) {
std::cout << n << std::endl;
}
number(float n) {
std::cout << n << std::endl;
}
};
void print_pair(std::pair<std::string, number> p) {}
这样,可以在没有error: call of overloaded ‘print_pair(<brace-enclosed initializer list>)’ is ambiguous
的情况下编译以下函数调用。
print_pair({"long", 12l});
print_pair({"float", 3.4f});
请注意,使用构造函数分别采用long
和float
的两个struct
,我们将回到相同的歧义问题。
- EASTL矢量<向量<int>>连续的
- "Inverse SFINAE"避免模棱两可的过载
- 操作员C++的模棱两可的过载
- 模棱两可的重载模板
- 调用重载的"<大括号括起来的初始值设定项列表>"对于对来说就足够了是模棱两可的
- 模棱两可的 != reverse_iterator运算符
- SFINAE不能防止模棱两可的操作员过载吗?
- VSCode 说 std::chrono 是模棱两可的,如果运算符<<重载
- 为什么对模板的调用不模棱两可?
- 修复重载运算符的使用'+'模棱两可?
- 为什么同时覆盖全局新运算符和特定于类的运算符不是模棱两可的行为?
- Antlr4 C++访问模棱两可的分支
- 模棱两可的调用 - 模板化函数
- 在SESHAT中,对"元组"的引用是模棱两可的
- C++17 年与 Clang 的模棱两可的部分专业化
- gcc 中的模棱两可的运算符
- 将 NULL 转换为长不是模棱两可吗?
- C++ lambda 模棱两可的调用
- 带有模板的循环缓冲区在Keil MDK5上是模棱两可的错误?
- C++11 中对超载'ref(Select::Expressions::Code&)'的调用模棱两可