带有 SFINAE 虚拟参数的模糊模板 [英] Ambiguous template with SFINAE dummy parameter

查看:40
本文介绍了带有 SFINAE 虚拟参数的模糊模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑这样一种情况,需要在内部使用另一个模板 g(例如可能是一些 enable_if 表达式)验证类型 T另一个模板的虚拟参数,如下所示:

Consider a case where one needs to verify a type T with another template g (could be some enable_if expression, for example) inside a dummy parameter of another template, like this:

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; }

在这里,为了简单起见,g 并没有真正做任何事情.Case B 中的第二个参数是在非推导的上下文中,因此直觉上人们会认为 Case BCase A 更专业.可悲的是,gcc 和 clang 都会抱怨模板在上面的实例化中不明确.

Here, for the sake of simplicity g doesn't really do anything. The second parameter in Case B is in a nondeduced context, therefore intuitively one would think that Case B is more specialized than Case A. Sadly, both gcc and clang will complain that the template is ambiguous in the instantiation above.

如果要删除虚拟参数,则它编译得很好.添加非推导参数如何以某种方式破坏 T*T 更专业化的合理预期?

If the dummy parameter were to be removed, then it compiles just fine. How does the addition of a nondeduced parameter somehow destroy the reasonable expectation that T* is more specialized than T?

这是使用替换算法的快速检查:

Here's a quick check using the substitution algorithm:

   f<Q , void      >
-> f<T*, g<Q>::type> // [failed]

   f<Q*, g<Q>::type>
-> f<T , void      > // [to fail or not to fail?]
// One would assume that 2nd parameter is ignored, but guess not?

推荐答案

当出现歧义时,会使用模板的偏序来解决.然而,这种偏序是在模板上建立的,因为它们在任何替换发生之前,而不是之后(部分或完全)替换已经执行——这就是你期望通过在 typename g::type 中将 int 替换为 T,从而产生 typename g::type 因此(因为 g 的定义)void.

When ambiguity arises, partial ordering of templates is used to resolve it. However, this partial ordering is established on the templates as they are before any substitution happens, and not after (partial or complete) substitution has been performed - which is what you are expecting by replacing int for T in typename g<T>::type, which yields typename g<int>::type and therefore (because of the definition of g) void.

第 14.8.2.4/2 段指定了如何建立偏序(有关更详细的讨论,请参阅关于 SO 的这个答案下一段):

Paragraph 14.8.2.4/2 specifies how partial ordering is established (see this answer on SO for a more detailed discussion of the paragraph below):

使用两组类型来确定偏序.对于每个涉及的模板,原始函数类型和转换后的函数类型.[注:转换类型的创建在 14.5.6.2 中描述.—end note ] 推导过程使用转换后的类型作为参数模板和另一个模板的原始类型作为参数模板.这个过程做两次对于偏序比较中涉及的每种类型:一次使用转换后的 template-1 作为参数模板和模板 2 作为参数模板并再次使用转换后的模板 2作为参数模板,template-1 作为参数模板.

Two sets of types are used to determine the partial ordering. For each of the templates involved there is the original function type and the transformed function type. [ Note: The creation of the transformed type is described in 14.5.6.2. —end note ] The deduction process uses the transformed type as the argument template and the original type of the other template as the parameter template. This process is done twice for each type involved in the partial ordering comparison: once using the transformed template-1 as the argument template and template-2 as the parameter template and again using the transformed template-2 as the argument template and template-1 as the parameter template.

在进行任何替换之前,如果不知道 T 将假定什么值,您无法判断(编译器也无法判断)case B 是否比 案例 A.因此,这两个专业中没有一个比另一个更专业.

Before any substitution, without knowing what value T will assume, you cannot tell (and neither the compiler can tell) whether case B is more or less specialized than case A. Therefore, neither of the two specializations is more specialized than the other.

换句话说,问题不在于这种偏特化是否:

In other words, the question isn't whether this partial specialization:

template<class T> struct f<T, void>; // Case A

比这个更专业(通过部分替换获得):

Is more specialized than this one (obtained through partial substitution):

template<class T> struct f<T*, void>; // Case B

如果这就是你所拥有的,答案显然是 case B 更专业.相反,问题是对于任何可能的T,这个特化:

If that were what you have, the answer would be obviously that case B is more specialized. Instead, the question is whether for any possible T, this specialization:

template<class T> struct f<T, void>; // Case A

比这个更专业:

template<class T> struct f<T*, typename g<T>::type>; // Case B

由于不能为任何 T 建立,因此案例 B 既不比 案例 A 更专业,也不会更不专业,当两者都可行时,就会产生歧义.

Since that cannot be established for any T, case B is neither more specialized nor less specialized than case A, and when both are viable, you get an ambiguity.

如果您想知道偏序是否考虑了非推导上下文中的参数,这在第 14.8.2.4/11 段的注释中提到:

If you are wondering whether parameters in a non-deduced context are taken into consideration for partial ordering, this is mentioned in a note to Paragraph 14.8.2.4/11:

在大多数情况下,所有模板参数都必须有值才能推导成功,但对于部分排序目的 如果模板参数不在类型中使用,它可以保持没有值用于偏序.[ 注意:在非推导上下文中使用的模板参数被认为是用过的.——尾注 ]

In most cases, all template parameters must have values in order for deduction to succeed, but for partial ordering purposes a template parameter may remain without a value provided it is not used in the types being used for partial ordering. [ Note: A template parameter used in a non-deduced context is considered used. —end note ]

这篇关于带有 SFINAE 虚拟参数的模糊模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆