我遇到了一个看起来非常出乎意料的重载解析行为。下面的代码被拒绝,并通过GCC和铛多义性错误:使用默认功能模板参数的意外重载分辨率
template <typename T>
struct A
{
typedef T key_type;
};
template <typename T>
void foo(A<T> rng, T val);
template <typename T, typename U = T>
void foo(T, typename U::key_type);
int main()
{
A<int> i;
foo(i, 0);
}
的错误是:
test.cpp:16:5: error: call to 'foo' is ambiguous
foo(i, 0);
^~~
test.cpp:8:6: note: candidate function [with T = int]
void foo(A<T> rng, T val);
^
test.cpp:11:6: note: candidate function [with T = A<int>, U = A<int>]
void foo(T, typename U::key_type);
^
我希望既要精确匹配,但第一个重载在偏序取胜,因为在第一个参数A<T>
比T
更专业。
什么最令我嫉妒的是,如果我改变了第二签名:
template <typename T, typename U = T>
void foo(T, typename T::key_type);
GCC和铛现在接受的代码,并选择以我原本预计第一批超载。
我不明白这种改变会如何改变行为:我所做的只是使用一个模板参数,它既没有明确指定也没有用默认值(T
)推导出来(U
)。
然后再次,改变之前的行为是意外的开始,所以也许我失去了一些东西。
有人能解释一下:
- 为什么第一种情况是模糊的;和
- 为什么我所做的改变解决了歧义?
万一它是相关的,我测试的编译器版本是gcc 4.8.0和最近的躯干构建的铿锵声。
+1,但看起来像一个简单的编译器错误给我。函数模板默认参数是新的。 – Potatoswatter
@Patatoswatter:我怀疑是这样,但是由于gcc和clang具有相同的行为,我想仔细检查一下,在报告它之前,我不知道这是否符合标准。 – HighCommander4
我注意到它们的错误,怪癖和诊断信息有很多重叠......无论法律含义如何,它们不完全是干净的房间设计。 – Potatoswatter