【问题标题】:Partial specialization of variadic templates可变参数模板的部分特化
【发布时间】:2012-01-14 07:24:39
【问题描述】:

考虑以下类模板“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 是模棱两可的。这是因为:

很明显#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,推导出的 T1 是 A1,Types 是空的。

A = X<A1>, P = X<T1, Types...>  =>  T1 = A1, Types = {}

第二步是使用#3'作为参数模板和#2'作为参数模板。给定唯一的参数类型是 X,根据 14.8.2.5/9(注意这一段最近由 N3281 修订),Args 被简单地忽略,推导出的 T1 为 A1,并且参数推导成功。

A = X<A1, Args...>, P = X<T1>  =>  T1 = A1 (Args is ignored)

终于,双向推论成功了。所以#2 和#3 一样专业。总之,X 是模棱两可的。

我的问题是:“我的解释正确吗?”

如果这个解释是正确的,那么 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 时,#3 和#4 不明确。

注意:在第一个示例中,GCC 4.7.0(快照)和 Clang 3.0 选择 #2。但是,这些编译器非常不可靠,以至于它们不遵循 N3281 的其他更改。

【问题讨论】:

  • 看来你是对的。空参数包不应影响部分排序。 gcc 似乎忽略了这一点,并将可变参数模板放在列表的较低位置,其他条件相同。例如。它在 14.5.6.2/5 处编译了一个示例,该示例被明确声明为模棱两可。
  • 正确性通常是单元测试的主题,尤其是在编程中。这可以确保您的解释是正确的,并且您可以高度自信地理解语言规范,这两者都可能在此处存在问题。
  • @n.m. this code 你在说什么?我从N3242 获取了该代码,链接自维基百科
  • 14.5.6.2/5(来自 N3242)“未使用的省略号和默认参数的存在对 function 模板的部分排序没有影响”(我的重点)。也许这只适用于函数模板,而这个问题是关于类模板的?
  • @Aaron:不,this one。这是 14.5.6.2 的最后一个示例。它编译虽然评论明确指出它不应该。

标签: c++ c++11 templates variadic-templates template-specialization


【解决方案1】:

14.8.2.4,第 11 节(我参考草案 N3242)。

在大多数情况下,所有模板参数都必须具有值才能 扣除成功,但出于部分排序目的,模板 如果未在 用于部分排序的类型。 [注:模板参数 在非推导上下文中使用被视为已使用。 ——尾注] [ 示例:

template <class T> T f(int); // #1
template <class T, class U> T f(U); // #2
void g() {
f<int>(1); // calls #1
}

在您的情况下,将使用#3。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 2017-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-15
    • 1970-01-01
    相关资源
    最近更新 更多