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

Hon*_*hen 9 c++ gcc templates clang c++11

我正在阅读Leor Zolman先生提出的一些名为"概述C++ 11和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...);
  }
};
Run Code Online (Sandbox Code Playgroud)

当使用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)?

T.C*_*.C. 10

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

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

6在声明类成员之后,可以在其类的范围内查找成员名称.

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

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

1)在类中声明的名称的潜在范围不仅包括名称声明点后面的声明性区域,还包括所有函数体,默认参数,异常规范和非支撑或等于初始值的声明区域 .该类中的静态数据成员(包括嵌套类中的这些内容).

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

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

declarator:
    ptr-declarator
    noptr-declarator parameters-and-qualifiers trailing-return-type
Run Code Online (Sandbox Code Playgroud)

因此,variadic版本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...);
}
Run Code Online (Sandbox Code Playgroud)

  • @hvd关于伟大思想的东西:) (3认同)