“void f(A<0>, tuple<T *...>)”比“void f(A<I>, tuple<T *...)”更为专业化吗?

14
#include <tuple>

template<int I>
struct A {};

template<int I, typename... T>
void f(A<I>, std::tuple<T *...>) {}

template<typename... T>
void f(A<0>, std::tuple<T *...>) {}

int main()
{
    f(A<0>{}, std::tuple<char*, int*, float*>{});
}

第二个重载的f更加专业化吗? g++ 4.9.2说这个调用是有歧义的,而clang 3.6.0则接受它。哪个编译器是正确的?

有趣的是,如果您将std::tuple<T *...>更改为std::tuple<T...>,g++就可以正常工作,但我不理解为什么。


MSVC 2013 也可以很愉快地使用这个:) - Rudolfs Bundulis
我怀疑gcc有问题,但是值模板参数可能存在一些晦涩的问题(标准在这方面往往比较古怪)。你能否不使用值来重现这个问题? - Yakk - Adam Nevraumont
clang 也可以与代码一起使用。 - Dietmar Kühl
2
@Yakk Repro 使用类型。 - Barry
1个回答

5
根据当前规则,第二个重载函数更为特化。一些带有合成值“@”的特化类型A<@>不能匹配到A<0>,但是A<0>可以匹配到A<I>(其中I=0)。这对第一组的不对称性是决定性的。对于第二个参数中的模式,使用T还是T*都无关紧要,因为对于该组来说,两种方式的推导都是成功的。
该漏洞仍然存在于主干版本中,并由@Barry报告为67228

请注意:分辨率CWG 1391可能会导致歧义。虽然我对此不确定。 - Columbo
是的,我认为分辨率不太对。看看Bogdan在这里的回答(https://dev59.com/P10Z5IYBdhLWcg3wfgYR#31735126),我认为他有一些很好的想法来解决措辞问题。 - Barry

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接