考虑以下简单(在模板问题的范围内)示例:
#include <iostream>
template <typename T>
struct identity;
template <>
struct identity<int> {
using type = int;
};
template<typename T> void bar(T, T ) { std::cout << "a\n"; }
template<typename T> void bar(T, typename identity<T>::type) { std::cout << "b\n"; }
int main ()
{
bar(0, 0);
}
Run Code Online (Sandbox Code Playgroud)
clang和gcc都在那里打印"a".根据[temp.deduct.partial]和[temp.func.order]中的规则,为了确定部分排序,我们需要合成一些独特的类型.所以我们有两次尝试扣除:
+---+-------------------------------+-------------------------------------------+
| | Parameters | Arguments |
+---+-------------------------------+-------------------------------------------+
| a | T, typename identity<T>::type | UniqueA, UniqueA |
| b | T, T | UniqueB, typename identity<UniqueB>::type |
+---+-------------------------------+-------------------------------------------+
Run Code Online (Sandbox Code Playgroud)
c++ templates partial-ordering language-lawyer overload-resolution
考虑一种情况,需要在T另一个模板的虚拟参数内验证具有另一个模板的类型g(enable_if例如,可能是某个表达式),如下所示:
template<class> struct g { typedef void type; };
template<class, class> struct f {};
template<class T> struct f<T, void> {}; // Case A
template<class T> struct f<T*, typename g<T>::type> {}; // Case B
int main() { f<int*, void> test; }
Run Code Online (Sandbox Code Playgroud)
在这里,为了简单起见,g并没有真正做任何事情.案例B中的第二个参数位于非弱化上下文中,因此直观地认为案例B比案例A更专业.可悲的是,gcc和clang都会抱怨模板在上面的实例化中是模棱两可的.
如果要删除虚拟参数,那么它编译就好了.如何添加一个非弱化参数会以某种方式破坏T*比这更专业的合理期望T?
这是使用替换算法的快速检查:
f<Q , void >
-> f<T*, g<Q>::type> // [failed]
f<Q*, g<Q>::type>
-> f<T , void > // [to fail …Run Code Online (Sandbox Code Playgroud) c++ sfinae template-specialization template-meta-programming