gcc可以编译一个可变参数模板,而clang则不能

时间:2014-10-09 08:52:49

标签: c++ templates c++11 gcc clang

我正在阅读Leor Zolman先生提出的一些名为An Overview of C++11 and C++14的幻灯片。在第35页,他介绍了一种使用decltype进行总和操作的方法。

struct Sum {
  template <typename T>
  static T sum(T n) {
    return n;
  }
  template <typename T, typename... Args>
  /// static T sum(T n, Args... rest) {
  static auto sum(T n, Args... rest) -> decltype(n + sum(rest...)) {
    return n + sum(rest...);
  }
};

当使用Sum::sum(1, 2.3, 4, 5); clang-3.6(来自svn)的这个片段无法用-std=c++11 / -std=c++1y编译时,但gcc-4.9成功。当然没有返回类型的类型推导都是编译,但是涉及类型转换并且无法获得预期的结果。

这是否表示一个clang bug,或者是因为gcc扩展(关于c ++ 11或c ++ 14)?

1 个答案:

答案 0 :(得分:10)

Clang的行为是正确的。这是一个GCC错误(并且演示文稿中的声明也不正确)。 §3.3.2[basic.scope.pdecl] / p1,6:

  

1名称的声明紧跟在其之后   完整的声明者(第8条)和初始化者之前(如果有的话),   除非如下所述。

     

6在声明类成员之后,成员名称可以   被提升到同班的范围内。

§3.3.7[basic.scope.class] / p1说

  

以下规则描述了在类中声明的名称范围。

     

1)类中声明的名称的潜在范围不仅包括在内   名称的声明点后的声明区域,   而且所有函数体,默认参数,    exception-specifications brace-or-equal-initializers   该类中的非静态数据成员(包括嵌套中的这些内容)   类)。

trailing-return-types 不在该列表中。

尾随返回类型是声明符的一部分(§8[dcl.decl] / p4):

declarator:
    ptr-declarator
    noptr-declarator parameters-and-qualifiers trailing-return-type

因此sum的可变版本不在其自己的 trailing-return-type 范围内,并且无法通过名称查找找到。

在C ++ 14中,只需使用实际的返回类型推导(并省略尾随返回类型)。在C ++ 11中,您可以使用类模板和简单转发的函数模板:

template<class T, class... Args>
struct Sum {
    static auto sum(T n, Args... rest) -> decltype(n + Sum<Args...>::sum(rest...)) {
        return n + Sum<Args...>::sum(rest...);
    }
};

template<class T>
struct Sum<T>{
    static T sum(T n) { return n; }
};

template<class T, class... Args>
auto sum(T n, Args... rest) -> decltype(Sum<T, Args...>::sum(n, rest...)){
    return Sum<T, Args...>::sum(n, rest...);
}