类模板专业化部分排序和函数综合 [英] Class template specialization partial ordering and function synthesis

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

问题描述

选择哪个类模板专业化优先的规则包括将这些专业化重写为功能模板,并通过功能模板的排序规则[temp.class.order]确定哪个功能模板更专业.考虑这个例子,然后:

The rules for picking which class template specialization is preferred involve rewriting the specializations into function templates and determining which function template is more specialized via the ordering rules for function templates [temp.class.order]. Consider this example, then:

#include <iostream>

template <class T> struct voider { using type = void; };
template <class T> using void_t = typename voider<T>::type;

template <class T, class U> struct A { };

template <class T> int foo(A<T, void_t<T>> ) { return 1; }
template <class T> int foo(A<T*, void> )     { return 2; }

int main() {
    std::cout << foo(A<int*, void>{});
}

gcc和clang都在这里打印2.这在前面的示例中是有道理的-针对非推导上下文(针对void_t<T>void)被忽略,因此针对<X*, void><T, void_t<T>>推导成功,但针对<Y, void_t<Y>><T*, void>推导都失败.论点.好吧.

Both gcc and clang print 2 here. This makes sense with some previous examples - deducing against a non-deduced context (void against void_t<T>) is just ignored, so deducing <T, void_t<T>> against <X*, void> succeeds but deducing <T*, void> against <Y, void_t<Y>> fails in both arguments. Fine.

现在考虑这种概括:

#include <iostream>

template <class T> struct voider { using type = void; };
template <class T> using void_t = typename voider<T>::type;

template <int I> struct int_ { static constexpr int value = I; };

template <class T, class U> struct A      : int_<0> { };
template <class T> struct A<T, void_t<T>> : int_<1> { };
template <class T> struct A<T*, void>     : int_<2> { };

int main() {
    std::cout << A<int*, void>::value << '\n';
}

clang和gcc都在12之间将这种专业化描述为模棱两可.但为什么?合成的功能模板不是模棱两可的.这两种情况有什么区别?

Both clang and gcc report this specialization as ambiguous, between 1 and 2. But why? The synthesized function templates aren't ambiguous. What's the difference between these two cases?

推荐答案

Clang与GCC兼容(并且与依赖于这两种行为的现有代码兼容).

Clang is being GCC-compatible (and compatible with existing code that depends on both of these behaviors).

考虑 [temp.deduct.type] p1 :

[...]尝试查找替换为后的P的模板参数值(类型参数的类型,非类型参数的值或模板参数的模板)推导值(称为推导A),与A兼容.

[...] an attempt is made to find template argument values (a type for a type parameter, a value for a non-type parameter, or a template for a template parameter) that will make P, after substitution of the deduced values (call it the deduced A), compatible with A.

问题的症结在于兼容"在这里的含义.

The crux of the issue is what "compatible" means here.

部分订购功能模板时,Clang仅在两个方向上推导;如果推论在一个方向上成功,但在另一方向上不成功,则假定结果将是兼容的",并将其用作排序结果.

When partially ordering function templates, Clang merely deduces in both directions; if deduction succeeds in one direction but not the other, it assumes that means the result will be "compatible", and uses that as the ordering result.

但是,当部分订购类模板的部分专业知识时,Clang会将兼容"解释为相同"的含义.因此,只有将推导的论点中的一个推导替换为另一个,才能重现原始的局部专业化,它才认为一个局部专业化比另一个局部专业化更专业.

When partially ordering class template partial specializations, however, Clang interprets "compatible" as meaning "the same". Therefore it only considers one partial specialization to be more specialized than another if substituting the deduced arguments from one of them into the other would reproduce the original partial specialization.

更改这两个中的任何一个以匹配其他两个都会破坏大量的实际代码. :(

Changing either of these two to match the other breaks substantial amounts of real code. :(

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

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