SFINAE和部分类模板专业化

blu*_*rni 30 c++ templates c++11 c++14

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

因此,在阅读描述提议的void_t别名/检测习语的论文时,我有点困惑:

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文档,它明确提到了部分特化).

我误解了上述文件中的要点还是真的是灰色区域?

Bar*_*rry 15

我想争辩说,由于措辞缺陷,标准不支持部分专业化的SFINAE.让我们从[temp.class.spec.match]开始:

如果可以从实际模板参数列表推导出部分特化的模板参数,则部分特化匹配给定的实际模板参数列表(14.8.2).

并且,从[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);
}
Run Code Online (Sandbox Code Playgroud)

查找名称查找X主要,用T == char, U == float.我们看一个部分特化,看看它是否"匹配" - 这意味着模板参数"可以推导出" - 也就是说:

+-------------+--------+-------------------------------------------------+
|             | arg1     arg2                                            |
+-------------+--------+-------------------------------------------------+
| deduce T in | T      | enable_if_t<(sizeof(T) > sizeof(float), float>  |
| from        | char   | float                                           |
+-------------+--------+-------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

正常的模板扣除规则适用.第二个"论证"是一个不可推导的背景,所以我们推断Tchar.sizeof(char) > sizeof(float),是假的,并且enable_if_t<false, float>是无效类型,因此类型扣除应该失败...但是,只能发生扣减失败

函数类型及其模板参数类型的直接上下文中

我们没有处理函数类型或函数模板参数类型,我们正在处理类模板参数类型.一个类不是一个函数,所以如果我们从字面上理解所有内容,SFINAE排除不应该适用 - 并且修改后的CWG示例应该导致硬错误.

然而,规则的精神似乎更符合以下方面:

只有扣除过程的直接上下文中的无效类型和表达式才会导致扣减失败.

我不知道具体排除类部分专业化演绎的原因是什么.此外,类模板部分特化的部分排序也看起来像函数.来自[temp.class.order]:

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

因此,标准已经在下一部分中展示了类模板部分特化和功能模板之间的二元性.事实上,这仅适用于部分特化排序,而不是在部分特化参数推导期间的替换失败,这使我感到有缺陷.


示例本身就是X<double, float>.但这实际上并没有证明或要求SFINAE,因为任何地方都不会有替代失败.