简体   繁体   English

SFINAE和部分类模板专业化

[英]SFINAE and partial class template specializations

I have been using SFINAE-based approaches for quite some time, especially to enable/disable specific class template specializations via std::enable_if . 我已经使用基于SFINAE的方法已经有一段时间了,特别是通过std::enable_if来启用/禁用特定的类模板特化。

I was thus a bit puzzled while reading the paper describing the proposed void_t alias / detection idiom: 因此,在阅读描述拟议的void_t别名/检测惯用语的论文时,我有点困惑:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf

Section 4 is devoted to the discussion of the validity of the idiom, and refers to a discussion in which two parties argue about the applicability of SFINAE in partial class template specializations (with Richard Smith pointing out that the standard is lacking wording about this topic). 第4节专门讨论成语的有效性,并参考了一个讨论,其中两方争论SFINAE在部分类模板专业化中的适用性(理查德史密斯指出该标准缺乏关于该主题的措辞) 。 Towards the end of the section, the following CWG issue is mentioned 在本节末尾,提到了以下CWG问题

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2054 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2054

Here again it is stated that the standard does not explicitly allows the example reproduced in the issue. 这里再次声明该标准没有明确地允许在该问题中再现的示例。

I am a bit baffled because it seems to me that, eg, the usage of enable_if in partial specializations has been standard practice for quite some time (see for instance the Boost documentation, which explicitly mentions partial specializations). 我有点困惑,因为在我看来,例如,在部分特化中使用enable_if已经有一段时间的标准做法(例如参见Boost文档,它明确提到了部分特化)。

Am I misunderstanding the points in the documents above or is this really a grey area? 我误解了上述文件中的要点还是真的是灰色区域?

I would like to argue that the Standard does not support SFINAE in partial specializations, due to a wording defect. 我想争辩说,由于措辞缺陷,标准不支持部分专业化的SFINAE。 Let's start with [temp.class.spec.match]: 让我们从[temp.class.spec.match]开始:

A partial specialization matches a given actual template argument list if the template arguments of the partial specialization can be deduced from the actual template argument list (14.8.2). 如果可以从实际模板参数列表推导出部分特化的模板参数,则部分特化匹配给定的实际模板参数列表(14.8.2)。

And, from [temp.deduct], the SFINAE clause: 并且,从[temp.deduct],SFINAE条款:

If a substitution results in an invalid type or expression, type deduction fails. 如果替换导致无效的类型或表达式,则类型推导失败。 An invalid type or expression is one that would be ill-formed, with a diagnostic required, if written using the substituted arguments. 如果使用替换参数写入,则无效的类型或表达式将是格式错误的,需要诊断。 [ Note: If no diagnostic is required, the program is still ill-formed. [注意:如果不需要诊断,程序仍然是不正确的。 Access checking is done as part of the substitution process. 访问检查是替换过程的一部分。 —end note ] Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure. -end note]只有函数类型的直接上下文中无效类型和表达式及其模板参数类型才会导致演绎失败。

The slightly-modified example from CWG is: 来自CWG的略微修改的示例是:

template <class T, class U> struct X   {
    typedef char member;
};

template<class T> struct X<T,
     typename enable_if<(sizeof(T)>sizeof(
 float)), float>::type>
{
    typedef long long member;
};

int main() {
    cout << sizeof(X<char, float>::member);
}

Name lookup on X finds the primary, with T == char, U == float . X上的名称查找找到主要内容, T == char, U == float We look at the one partial specialization, and see if it "matches" - which means that the template arguments "can be deduced" - which is to say: 我们看一个部分特化,看看它是否“匹配” - 这意味着模板参数“可以推导出” - 也就是说:

+-------------+--------+-------------------------------------------------+
|             | arg1     arg2                                            |
+-------------+--------+-------------------------------------------------+
| deduce T in | T      | enable_if_t<(sizeof(T) > sizeof(float), float>  |
| from        | char   | float                                           |
+-------------+--------+-------------------------------------------------+

Normal template deduction rules apply. 正常的模板扣除规则适用。 The second "argument" is a non-deducible context, so we deduce T as char . 第二个“参数”是一个不可推导的上下文,因此我们将T推导为char sizeof(char) > sizeof(float) , is false, and enable_if_t<false, float> is an invalid type, so type deduction should fail... but, deduction failure can only occur sizeof(char) > sizeof(float) ,为false,并且enable_if_t<false, float>是无效类型,因此类型推导应该失败...但是,只能进行扣减失败

in the immediate context of the function type and its template parameter types 函数类型及其模板参数类型的直接上下文中

and we're not dealing with a function type or function template parameter types, we're dealing with class template parameter types. 我们没有处理函数类型或函数模板参数类型,我们正在处理类模板参数类型。 A class is not a function, so the SFINAE exclusion should not apply if we take everything literally - and the modified CWG example should lead to a hard error. 一个类不是一个函数,所以如果我们从字面上理解所有内容,SFINAE排除不应该适用 - 并且修改后的CWG示例应该导致硬错误。

However, the spirit of the rule seems to be more along the lines of: 然而,规则的精神似乎更符合以下方面:

Only invalid types and expressions in the immediate context of the deduction process can result in a deduction failure. 只有扣除过程的直接上下文中的无效类型和表达式才会导致扣减失败。

I do not know what the reason would be to specifically exclude class partial specialization deduction. 我不知道具体排除类部分专业化演绎的原因是什么。 Furthermore, partial ordering of class template partial specializations also look like functions. 此外,类模板部分特化的部分排序也看起来像函数。 From [temp.class.order]: 来自[temp.class.order]:

For two class template partial specializations, the first is more specialized than the second if, given the following rewrite to two function templates , [...] 对于两个类模板部分特化,第一个比第二个更专业,如果给出以下重写到两个函数模板 ,[...]

The Standard thus already in the very next section exhibits a duality between class template partial specializations and function templates. 因此,标准已经在下一部分中展示了类模板部分特化和功能模板之间的二元性。 The fact that this only applies to partial specialization ordering, and not substitution failure during partial specialization argument deduction, strikes me as a defect. 事实上,这仅适用于部分特化排序,而不是在部分特化参数推导期间的替换失败,这使我感到有缺陷。


The example itself was X<double, float> . 示例本身是X<double, float> But this actually doesn't demonstrate or require SFINAE, as there would be no substitution failure anywhere. 但这实际上并没有证明或要求SFINAE,因为任何地方都不会有替代失败。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM