可变参数模板的部分特化

45

考虑以下类模板 'X' 及其部分特化。

template <class ...Types>
struct X {};               // #1

template <class T1>
struct X<T1> {};           // #2

template <class T1, class ...Types>
struct X<T1, Types...> {}; // #3

X<int> x;                  // #2 or #3 ?

我怀疑 X<int> 不够明确。原因如下:

显然,#2 和 #3 都比 #1 更加特殊化,现在我们要对比 #2 和 #3。根据 14.5.5.2,让我们来看看以下哪个是更加特殊化的:#2' 还是 #3'。

template <class T1>
void f(X<T1>);             // #2'

template <class T1, class ...Types>
void f(X<T1, Types...>);   // #3'

根据14.8.2.4,第一步是使用#2'作为参数模板和#3'作为参数模板进行模板参数推导。鉴于唯一的参数类型是X<A1>,推导出的T1是A1,Types为空。
A = X<A1>, P = X<T1, Types...>  =>  T1 = A1, Types = {}

第二步使用 #3' 作为参数模板,#2' 作为参数模板。鉴于唯一的参数类型是 X<A1, Args...>,根据 14.8.2.5/9(请注意,该段落最近由 N3281 修改),Args 被简单忽略,推导出的 T1 是 A1,参数推导成功。
A = X<A1, Args...>, P = X<T1>  =>  T1 = A1 (Args is ignored)

最终,双向参数推导成功。因此,#2与#3一样专业化。总之,X<int>是模棱两可的。
我的问题是:“我的解释正确吗?”
如果这种解释是正确的,在20.9.7.6/3中的'std::common_type'定义是不合适的。
template <class ...T>
struct common_type;            // #1

template <class T>
struct common_type<T>          // #2
{
    typedef T type;
};

template <class T, class U>
struct common_type<T, U>       // #3
{
    typedef
        decltype(true ? declval<T>() : declval<U>())
    type;
};

template <class T, class U, class ...V>
struct common_type<T, U, V...> // #4
{
    typedef typename
        common_type<typename common_type<T, U>::type, V...>::type
    type;
};

当使用common_type<A, B>时,#3和#4是模糊的。

注意:在第一个示例中,GCC 4.7.0(快照版)和Clang 3.0选择#2。然而,这些编译器不太可靠,它们不遵循N3281的其他更改。


1
看起来你是正确的。空参数包不应影响部分排序。gcc似乎忽略了这一点,并将可变模板放在列表中较低的位置,其他条件相等的情况下。例如,它编译了一个明确说明是有歧义的14.5.6.2/5示例。 - n. m.
@n.m. 这段代码(http://ideone.com/AHJ9s) 是你所说的吗?我从维基百科链接的N3242中取得了该代码。 - Aaron McDaid
@Aaron:不,这个链接是最后一个例子来自14.5.6.2。尽管注释明确说明它不应该编译,但它确实可以编译。 - n. m.
@Aaron:类模板的部分排序是通过函数模板的部分排序来表达的,如14.5.5.2所述。因此,它必须适用于两者。 - n. m.
(换句话说,我可能正在查看一个过时的文档,而且我也不是这方面的专家!) - Aaron McDaid
显示剩余3条评论
1个回答

8

14.8.2.4,第11节(我指的是草案N3242)。

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

template <class T> T f(int); // #1
template <class T, class U> T f(U); // #2
void g() {
f<int>(1); // calls #1
}
在您的情况下,将使用#3。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接