SFINAE和部分类模板专门化 [英] SFINAE and partial class template specializations

查看:126
本文介绍了SFINAE和部分类模板专门化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经使用基于SFINAE的方法相当一段时间,特别是通过 std :: enable_if 启用/禁用特定类模板专门化。



因此,我在阅读描述建议的 void_t 别名/检测idiom的论文时感到有点困惑:



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



第4节专门讨论习语的有效性,并参考了一个讨论,其中双方争论SFINAE在部分类模板专用化中的适用性(与理查德·史密斯指出,该标准缺乏关于这个主题的措辞)。在本节结束时,提到以下CWG问题



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



这里再次声明标准没有明确允许在问题中重现的例子。



我有点不解,因为在我看来,例如,在部分特化中使用 enable_if 已经是标准惯例了很长时间了(例如,Boost文档,其中明确提及部分特化)。

$


解决方案

p>我想说的是,由于一个措辞缺陷,该标准不支持SFINAE的部分特化。让我们从[temp.class.spec.match]开始:


部分特化与给定的实际模板参数列表匹配,如果模板参数




p>并且,从[temp.deduct],SFINAE子句:


如果替换导致无效的类型或表达式,失败。无效的类型或表达式是
,如果使用替换参数写入,那么将是不成立的,需要诊断。 [注意:
如果不需要诊断,程序仍然是错误的。访问检查是作为替换
过程的一部分完成的。 -end note]在函数类型及其模板参数类型的上下文中,只有无效的类型和表达式可能导致扣除失败。


来自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);
}

X 找到主键,用 T == char,U == float 。我们看看一个部分专业化,看看它是否匹配 - 这意味着模板参数可以推导 - 也就是说:

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

正常的模板扣除规则适用第二个因此我们推导出 T char sizeof(char)> sizeof float)是一个无效类型,所以类型扣除应该失败...但是,扣除失败只能在函数类型及其模板参数类型的上下文中


b $ b

,我们不处理函数类型或函数模板参数类型,我们正在处理类模板参数类型。一个类不是一个函数,所以如果我们从字面上看一切 - 而修改的CWG示例应该导致一个硬错误,SFINAE排除不应该适用。



但是,规则的精神似乎更符合以下条件:


只有在扣除过程的上下文中的无效类型和表达式才能导致扣款失败。


我不知道什么原因会特别排除类部分专业化扣除。此外,类模板部分特化的部分排序也看起来像函数。从[temp.class.order]:


对于两个类模板部分特化,第一个比第二个更专门,如果给定
以下重写到两个函数模板,[...]


在下一节中展示类模板部分特化和功能模板之间的对偶性。事实上,这只适用于部分专业化排序,而不是替代失败在部分专业化期间扣除,打击我作为一个缺陷。






示例本身为 X < float> 。但这实际上没有证明或要求SFINAE,因为在任何地方都没有替代失败。


I have been using SFINAE-based approaches for quite some time, especially to enable/disable specific class template specializations via std::enable_if.

I was thus a bit puzzled while reading the paper describing the proposed void_t alias / detection idiom:

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). Towards the end of the section, the following CWG issue is mentioned

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, e.g., 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).

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. Let's start with [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).

And, from [temp.deduct], the SFINAE clause:

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.

The slightly-modified example from CWG is:

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. 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. 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

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.

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]:

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>. But this actually doesn't demonstrate or require SFINAE, as there would be no substitution failure anywhere.

这篇关于SFINAE和部分类模板专门化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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