今天我正在阅读clang的C ++ 17支持页面。我注意到一些奇怪的事情。功能将模板模板参数与兼容参数匹配(P0522R0)被标记为部分,因为它必须通过开关激活。他们的注释says:
尽管是缺陷报告的解决方案,但默认情况下在所有语言版本中都禁用此功能,并且可以使用Clang 4中的标志-frelaxed-template-template-args显式启用此功能。标准的更改缺少模板部分排序的相应变化,导致合理且先前有效的代码的模糊错误。预计这个问题很快就会得到纠正。
激活此功能后,哪种结构会中断?为什么它会破坏代码以及如何破解代码?
答案 0 :(得分:14)
您可以使用以下代码:
template<template<typename> typename>
struct Foo {};
template<typename, typename = void>
struct Bar {};
Foo<Bar> unused;
如果没有缺陷解决方案,unused
将会格式不正确,因为foo
只使用一个模板参数而不是两个模板参数。如果您依赖于此(可能是SFINAE):
template<template<typename> typename>
void foo();
template<template<typename, typename> typename>
void foo();
template<typename, typename = void>
struct Bar {};
int main() {
foo<Bar>(); // ambiguous after resolution!
}
然后电话会失败!问题是部分排序没有相应的变化,因此两个候选函数都具有相同的可行性,并且调用是不明确的。
答案 1 :(得分:6)
更常见的情况是某些代码想要使用一组部分特化来检查模板参数,例如:
template<class> struct Foo;
template<template<class> class X, class T>
struct Foo<X<T>> { /* ... */ };
template<template<class, class> class X, class T, class U>
struct Foo<X<T, U>> { /* ... */ };
// etc., etc.
Foo<std::vector<int>>
现在格式不正确,没有适当的部分排序修复。